I'm currently implementing the repository pattern for my ASP.VNext application. I would like the methods to be asynchronous and filterable. So I have devised the following interface method:
Task<TEntity> GetOneAsync(Func<TEntity,bool> predicate);
and would like to implement it like this (with a private DbContext instance ctx
):
public async Task<MyEntity> GetOneAsync(Func<MyEntity,bool> predicate)
{
// compiler error
return await ctx.MyEntities.Where(predicate).FirstOrDefaultAsync();
}
However I can only use FirstOrDefaultAsync()
when hardcoding the predicate like this:
return await ctx.MyEntites.Where(e => e.Id == 1).FirstOrDefaultAsync();
When passing the predicate i only get the FirstOrDefault()
without the async option, so in order to make my method asynchronous I have to write
public async Task<MyEntity> GetOneAsync(Func<MyEntity,bool> predicate)
{
//save to a local variable to prevent calling a disposed DbContext
var entities = await Task.Run(() => ctx.Contracts.Where(predicate).FirstOrDefault());
return entities;
}
I have two questions regarding this:
Why is it not possible to access the FirstOrDefaultAsync()
method when passing a predicate?
Does my solution using await Task.Run(synchronousMethod)
achieve the same behavior as a call to FirstOrDefaultAsync()
would?
FirstOrDefaultAsync
is defined as an extension method for IQueryable<T>
.
ctx.MyEntities.Where(e => e.Id == 1)
returns IQueryable<MyEntity>
.
ctx.MyEntities.Where(predicate)
returns IEnumerable<MyEntity>
, because you're calling the Enumerable.Where
extension method, not the Queryable.Where
one.
To make it work, change predicate
from Func<MyEntity, bool>
to Expression<Func<MyEntity, bool>>
. This means predicate
is no longer just a function that gives the result you want, but a description of that function, that Entity Framework can then translate to SQL.
And no, using Func<MyEntity, bool>
within a task would not have the same behaviour. That would load rows from the db server without any filtering, and evaluate each and every one at the db client until a match is found. That would add a lot of overhead.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.