Is there a reason that the FindAsync()
method is omitted from the IDbSet<T>
interface? Find
is part of the interface, it seems odd the async version isn't available. I'm needing to cast to DbSet<T>
to access it, which is a bit cumbersome:
User user = await ((DbSet<User>)db.Users)
.FindAsync("de7d5d4a-9d0f-48ff-9478-d240cd5eb035");
Change the FindAsync method to FirstOrDefaultAsync(x => x.Id == yourId);
Here is how I tackled this in one of our projects:
One might consider wrapping the the Find method in a async-over-sync pattern which would provide offloading (and no scalability as true asynchronous methods do). However the caller must then be aware of this to make sure they aren't going to call methods on the context after calling the FindAsync method that might interfer. Making callers aware of a specific implementation isn't a very good design imho however because it can easily lead to problems. For the OP the IDbSet is a DbSet however so the call will be asynchronous.
I believe the correct way these days (since EF 6) involves inheriting from DbSet instead of implementing IDbSet.
Use this extension to solved the FindAsync problem
If you own the consumer of
IDbSet<T>
, which I assume that you do because you want to have access toFindAsync()
from within the consumer, then a simple solution is to create your own interface that includes IDbSet and contains whicheverFindAsync()
method that you want to use:This solves the problem of not having to cast to DbSet - which, by the way, blows away the abstractness benefit of contract coding. But this also introduces its own set of problems.
A better solution (imo) that requires a bit more work is to define an interface that contains only the members that you want to use in what would otherwise be your DbSet object, subclass DbSet while implementing the interface, then use that interface in your code:
This is an Adapter pattern, really. It decouples the interface that your code expects from the interface that Entity Framework provides. Right now, they are identical - which is why the implementation does nothing except inherit
DbSet<T>
. But later on they might diverge. At that point you will still be able to use the latest DbSet without breaking your code.