Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FirstOrDefaultAsync() & SingleOrDefaultAsync() vs FindAsync() EFCore

We have 3 different approaches to get single items from EFCore they are FirstOrDefaultAsync(), SingleOrDefaultAsync() (including its versions with not default value returned, also we have FindAsync() and maybe more with the same purpose like LastOrDefaultAsync().

     var findItem = await dbContext.TodoItems        .FindAsync(request.Id)        .ConfigureAwait(false);       var firstItem = await dbContext.TodoItems         .FirstOrDefaultAsync(i => i.Id == request.Id)         .ConfigureAwait(false);       var singleItem = await dbContext.TodoItems         .SingleOrDefaultAsync(i => i.Id == request.Id)         .ConfigureAwait(false); 

I would like to know the differences between each one of them. So far what I know is that we FirstOrDefaultAsync() to get the first given a condition, (usually using this because we know that more than one item can satisfy the condition), on the other hand we use SingleOrDefaultAsync() because we know that there is only one possible match to find, and FindAsync() to get an item given its primary key.

I think FirstOrDefaultAsync() & SingleOrDefaultAsync() always hit the database (not sure about this), and FindAsync() this is what Microsoft docs says:

Asynchronously finds an entity with the given primary key values. If an entity with the given primary key values exists in the context, then it is returned immediately without making a request to the store. Otherwise, a request is made to the store for an entity with the given primary key values and this entity, if found, is attached to the context and returned. If no entity is found in the context or the store, then null is returned.

So my question is, if our given condition used for FirstOrDefault(), SingleOrDefault() and FindAsync() is the primary key, do we have any actual difference?

What I think is that the first time they are used always hit the db, but what about the next calls?. And probably EFCore could use the same context to get the values for FirstOrDefault() and SingleOrDefault() as it does for FindAsync(), maybe?.

like image 778
Diego Osornio Avatar asked Feb 22 '19 03:02

Diego Osornio


2 Answers

FindAsync

In much of the scaffolded code, FindAsync can be used in place of FirstOrDefaultAsync.

SingleOrDefaultAsync

fetches more data and does unnecessary work. throws an exception if there's more than one entity that fits the filter part.

FirstOrDefaultAsync

doesn't throw if there's more than one entity that fits the filter part.

https://docs.microsoft.com/en-us/aspnet/core/data/ef-rp/crud?view=aspnetcore-2.2#singleordefaultasync-vs-firstordefaultasync

like image 164
Joey Phillips Avatar answered Sep 17 '22 10:09

Joey Phillips


FindAsync:

  • Accepts primary key
  • Optimized for finding an entity with a primary key, by returning the entity without hitting the database if the entity was tracked.
  • Can't use the include method with FindAsync.
  • Returns default value if no match was found.

FirstOrDefaultAsync:

  • Accepts Expression.
  • Better choice over FindAsync if related entities are needed.
  • Returns default value if no match was found.

SingleOrDefaultAsync:

  • Accepts Expression.
  • Returns default value if no match was found.
  • Throws an exception if more than one match were found.
like image 25
IBRA Avatar answered Sep 19 '22 10:09

IBRA