Antworten:
Ich weiß, dass andere geschrieben haben, warum Sie das eine oder das andere verwenden, aber ich dachte, ich würde veranschaulichen, warum Sie das eine NICHT verwenden sollten, wenn Sie das andere meinen .
Hinweis: In meinem Code, ich in der Regel verwenden FirstOrDefault()
und , SingleOrDefault()
aber das ist eine andere Frage.
Nehmen Sie zum Beispiel eine Tabelle, die Customers
mit einem zusammengesetzten Schlüssel ( ID
, Lang
) in verschiedenen Sprachen gespeichert wird :
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();
Dieser obige Code führt einen möglichen Logikfehler ein (schwer zu verfolgen). Es wird mehr als ein Datensatz zurückgegeben (vorausgesetzt, Sie haben den Kundendatensatz in mehreren Sprachen), aber es wird immer nur der erste zurückgegeben ... was manchmal funktioniert ... aber nicht andere. Es ist unvorhersehbar.
Da Sie beabsichtigen, eine einmalige Customer
Verwendung zurückzugeben Single()
;
Folgendes würde eine Ausnahme auslösen (was in diesem Fall gewünscht wird):
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single();
Dann schlägst du dich einfach auf die Stirn und sagst dir ... OOPS! Ich habe das Sprachfeld vergessen! Es folgt die richtige Version:
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 && c.Lang == "en" ).Single();
First()
ist im folgenden Szenario nützlich:
DBContext db = new DBContext();
NewsItem newsitem = db.NewsItems.OrderByDescending( n => n.AddedDate ).First();
Es wird EIN Objekt zurückgegeben, und da Sie die Sortierung verwenden, ist es der letzte Datensatz, der zurückgegeben wird.
Mit Single()
wenn Sie es ausdrücklich immer 1 Datensatz zurückkehren wird dazu beitragen , logische Fehler fühlen Sie vermeiden sollten.
customers.Where(predicate).Single()
customers.Single(predicate)
?
Single löst eine Ausnahme aus, wenn mehr als ein Datensatz gefunden wird, der den Kriterien entspricht. Zuerst wird immer der erste Datensatz aus der Liste ausgewählt. Wenn die Abfrage nur 1 Datensatz zurückgibt, können Sie fortfahren First()
.
Beide lösen eine InvalidOperationException
Ausnahme aus, wenn die Sammlung leer ist. Alternativ können Sie verwenden SingleOrDefault()
. Dies löst keine Ausnahme aus, wenn die Liste leer ist
Single()
Gibt ein einzelnes bestimmtes Element einer Abfrage zurück
Bei Verwendung : Wenn genau 1 Element erwartet wird; nicht 0 oder mehr als 1. Wenn die Liste leer ist oder mehr als ein Element enthält, wird eine Ausnahme "Sequenz enthält mehr als ein Element" ausgelöst.
SingleOrDefault ()
Gibt ein einzelnes bestimmtes Element einer Abfrage oder einen Standardwert zurück, wenn kein Ergebnis gefunden wird
Bei Verwendung : Wenn 0 oder 1 Elemente erwartet werden. Es wird eine Ausnahme ausgelöst, wenn die Liste 2 oder mehr Elemente enthält.
Zuerst()
Gibt das erste Element einer Abfrage mit mehreren Ergebnissen zurück.
Bei Verwendung : Wenn 1 oder mehrere Elemente erwartet werden und Sie nur das erste möchten. Es wird eine Ausnahme ausgelöst, wenn die Liste keine Elemente enthält.
FirstOrDefault ()
Gibt das erste Element einer Liste mit einer beliebigen Anzahl von Elementen oder einen Standardwert zurück, wenn die Liste leer ist.
Bei Verwendung : Wenn mehrere Elemente erwartet werden und Sie nur das erste möchten. Oder die Liste ist leer und Sie möchten einen Standardwert für den angegebenen Typ wie
default(MyObjectType)
. Beispiel: Wenn der Listentyp istlist<int>
, wird die erste Nummer aus der Liste zurückgegeben oder 0, wenn die Liste leer ist. Wenn dies der Fall istlist<string>
, wird die erste Zeichenfolge aus der Liste zurückgegeben oder null, wenn die Liste leer ist.
First
wenn 1 oder mehr Elemente erwartet werden , nicht nur "mehr als 1" und FirstOrDefault
mit einer beliebigen Anzahl von Elementen.
Es gibt einen subtilen semantischen Unterschied zwischen diesen beiden Methoden.
Verwenden Sie Single
diese Option , um das erste (und einzige) Element aus einer Sequenz abzurufen, die ein Element und nicht mehr enthalten soll. Wenn die Sequenz mehr als ein Element enthält, wird durch Ihren Aufruf von Single
eine Ausnahme ausgelöst, da Sie angegeben haben, dass nur ein Element vorhanden sein soll.
Verwenden Sie First
diese Option , um das erste Element aus einer Sequenz abzurufen, die eine beliebige Anzahl von Elementen enthalten kann. Wenn die Sequenz mehr als ein Element enthält, wird Ihr Aufruf vonFirst
keine Ausnahme ausgelöst, da Sie angegeben haben, dass Sie nur das erste Element in der Sequenz benötigen und es egal ist, ob weitere vorhanden sind.
Wenn die Sequenz keine Elemente enthält, werden bei beiden Methodenaufrufen Ausnahmen ausgelöst, da beide Methoden erwarten, dass mindestens ein Element vorhanden ist.
Wenn Sie nicht ausdrücklich möchten, dass eine Ausnahme für den Fall ausgelöst wird, dass mehr als ein Element vorhanden ist, verwenden SieFirst()
.
Beide sind effizient, nehmen Sie den ersten Punkt. First()
ist etwas effizienter, da es nicht die Mühe macht, zu überprüfen, ob es ein zweites Element gibt.
Der einzige Unterschied besteht darin, Single()
dass zunächst nur ein Element in der Aufzählung erwartet wird und eine Ausnahme ausgelöst wird, wenn mehr als ein Element vorhanden ist. Sie verwenden .Single()
diese Option , wenn in diesem Fall speziell eine Ausnahme ausgelöst werden soll.
Wenn ich mich erinnere, prüft Single (), ob nach dem ersten ein anderes Element vorhanden ist (und löst eine Ausnahme aus, wenn dies der Fall ist), während First () nach dem Abrufen stoppt. Beide lösen eine Ausnahme aus, wenn die Sequenz leer ist.
Persönlich benutze ich immer First ().
In Bezug auf die Leistung: Ein Mitarbeiter und ich diskutierten die Leistung von Single vs First (oder SingleOrDefault vs FirstOrDefault) und ich argumentierte für den Punkt, dass First (oder FirstOrDefault) schneller sein und die Leistung verbessern würde (ich möchte unsere App entwickeln) schneller laufen).
Ich habe mehrere Beiträge zu Stack Overflow gelesen, in denen dies diskutiert wird. Einige sagen, dass es kleine Leistungssteigerungen gibt, wenn First anstelle von Single verwendet wird. Dies liegt daran, dass First einfach das erste Element zurückgibt, während Single alle Ergebnisse scannen muss, um sicherzustellen, dass kein Duplikat vorhanden ist (dh, wenn das Element in der ersten Zeile der Tabelle gefunden wird, wird weiterhin jede zweite Zeile gescannt Stellen Sie sicher, dass es keinen zweiten Wert gibt, der der Bedingung entspricht, die dann einen Fehler auslösen würde. Ich hatte das Gefühl, auf einem soliden Boden zu stehen, da „First“ schneller als „Single“ war, und machte mich daran, dies zu beweisen und die Debatte zu beenden.
Ich habe einen Test in meiner Datenbank eingerichtet und 1.000.000 Zeilen ID UniqueIdentifier Foreign UniqueIdentifier Info nvarchar (50) hinzugefügt (gefüllt mit Zeichenfolgen von „0“ bis „999.9999“.
Ich habe die Daten geladen und die ID als Primärschlüsselfeld festgelegt.
Mit LinqPad wollte ich zeigen, dass es viel schlimmer wäre, wenn Sie mit Single nach einem Wert für 'Foreign' oder 'Info' suchen, als mit First.
Ich kann die Ergebnisse nicht erklären. In fast allen Fällen war die Verwendung von Single oder SingleOrDefault etwas schneller. Das ergibt für mich keinen logischen Sinn, aber ich wollte das teilen.
Beispiel: Ich habe die folgenden Abfragen verwendet:
var q = TestTables.First(x=>x.Info == "314638") ;
//Vs.
Var q = TestTables.Single(x=>x.Info =="314638") ; //(this was slightly faster to my surprise)
Ich habe ähnliche Abfragen im Schlüsselfeld "Fremd" versucht, bei denen es sich nicht um indizierte Überlegungen handelte, die beweisen würden, dass First schneller ist, Single jedoch in meinen Tests immer etwas schneller.
Sie sind anders. Beide behaupten, dass die Ergebnismenge nicht leer ist, aber single behauptet auch, dass es nicht mehr als 1 Ergebnis gibt. Ich persönlich verwende Single in Fällen, in denen ich nur ein Ergebnis erwarte, nur weil es ein Fehler ist, mehr als ein Ergebnis zurückzubekommen, und wahrscheinlich als solches behandelt werden sollte.
Sie können ein einfaches Beispiel ausprobieren, um einen Unterschied zu erzielen. Ausnahme wird in Zeile 3 ausgelöst;
List<int> records = new List<int>{1,1,3,4,5,6};
var record = records.First(x => x == 1);
record = records.Single(x => x == 1);
Die Datensätze in der Entität Mitarbeiter:
Employeeid = 1
: Nur ein Mitarbeiter mit dieser ID
Firstname = Robert
: Mehr als ein Mitarbeiter mit diesem Namen
Employeeid = 10
: Kein Mitarbeiter mit dieser ID
Jetzt ist es notwendig zu verstehen, was Single()
und was First()
im Detail bedeutet.
Single()
Single () wird verwendet, um einen einzelnen Datensatz zurückzugeben, der eindeutig in einer Tabelle vorhanden ist. Die folgende Abfrage gibt also den Mitarbeiter zurück, dessen, employeed =1
weil wir nur einen Mitarbeiter haben, dessen 1 Employeed
ist. Wenn wir zwei Datensätze für EmployeeId = 1
haben, wird ein Fehler ausgegeben (siehe die Fehler unten in der zweiten Abfrage, für die wir ein Beispiel verwenden Firstname
.
Employee.Single(e => e.Employeeid == 1)
Das obige gibt einen einzelnen Datensatz zurück, der 1 hat employeeId
Employee.Single(e => e.Firstname == "Robert")
Das Obige löst eine Ausnahme aus, da mehrere Datensätze in der Tabelle für enthalten sind FirstName='Robert'
. Die Ausnahme wird sein
InvalidOperationException: Die Sequenz enthält mehr als ein Element
Employee.Single(e => e.Employeeid == 10)
Dies löst erneut eine Ausnahme aus, da für id = 10 kein Datensatz vorhanden ist. Die Ausnahme wird sein
InvalidOperationException: Die Sequenz enthält keine Elemente.
Denn EmployeeId = 10
es wird null zurückgeben, aber während wir es benutzen Single()
, wird es einen Fehler auslösen. Um Nullfehler zu behandeln, sollten wir verwenden SingleOrDefault()
.
Zuerst()
First () gibt aus mehreren Datensätzen die entsprechenden Datensätze zurück, die in aufsteigender Reihenfolge sortiert sind, birthdate
sodass 'Robert' zurückgegeben wird, der am ältesten ist.
Employee.OrderBy(e => e. Birthdate)
.First(e => e.Firstname == "Robert")
Oben sollte der älteste zurückgegeben werden, Robert gemäß DOB.
Employee.OrderBy(e => e. Birthdate)
.First(e => e.Employeeid == 10)
Oben wird eine Ausnahme ausgelöst, da kein Datensatz für id = 10 vorhanden ist. Um eine Null - Ausnahme zu vermeiden wir verwenden sollten , FirstOrDefault()
als vielmehr First()
.
Hinweis: Wir können nur First()
/ verwenden, Single()
wenn wir absolut sicher sind, dass kein Nullwert zurückgegeben werden kann.
Verwenden Sie in beiden Funktionen SingleOrDefault () ODER FirstOrDefault (), das eine Null-Ausnahme behandelt. Wenn kein Datensatz gefunden wird, wird Null zurückgegeben.