LINQ Single vs First
Solution 1:
If you're expecting a Single record, it's always good to be explicit in your code.
I know others have written why you use one or the other, but I thought I'd illustrate why you should NOT use one, when you mean the other.
Note: In my code, I will typically use FirstOrDefault()
and SingleOrDefault()
but that's a different question.
Take, for example, a table that stores Customers
in different languages using a Composite Key ( ID
, Lang
):
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();
This code above introduces a possible logic error ( difficult to trace ). It will return more than one record ( assuming you have the customer record in multiple languages ) but it will always return only the first one... which may work sometimes... but not others. It's unpredictable.
Since your intent is to return a Single Customer
use Single()
;
The following would throw an exception ( which is what you want in this case ):
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single();
Then, you simply hit yourself on the forehead and say to yourself... OOPS! I forgot the language field! Following is the correct version:
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 && c.Lang == "en" ).Single();
First()
is useful in the following scenario:
DBContext db = new DBContext();
NewsItem newsitem = db.NewsItems.OrderByDescending( n => n.AddedDate ).First();
It will return ONE object, and since you're using sorting, it will be the most recent record that is returned.
Using Single()
when you feel it should explicitly always return 1 record will help you avoid logic errors.
Solution 2:
Single will throw an exception if it finds more than one record matching the criteria.
First will always select the first record from the list. If the query returns just 1 record, you can go with First()
.
Both will throw an InvalidOperationException
exception if the collection is empty.
Alternatively you can use SingleOrDefault()
. This won't throw an exception if the list is empty