I have the following code that used to convert Func
-based filters to Expression
and filter the data in Entity Framework Core 2.2:
public async Task<TType> GetDataAsync<TType>(Func<TType, bool> filtering = null) where TType : class
{
Expression<Func<TType, bool>> filteringExpression = (type) => filtering(type);
if (filtering != null)
//return await myContext.Set<TType>().FirstOrDefaultAsync(filteringExpression);
return await myContext.Set<TType>().Where(filteringExpression ).FirstOrDefaultAsync();
return await myContext.Set<TType>().FirstOrDefaultAsync();
}
This is how I use it:
public async Task<DataLog> GetDataLogByID(Guid dataLogID) => await GetDataAsync<DataLog>(dataLog => dataLog.ID == dataLogID);
(Un)fortunately, when I upgraded to Entity Framework Core 3.0, the code threw an InvalidOperationException
as the expression can't be turned into SQL query (although it filters only a property that matches a database column):
System.InvalidOperationException: 'The LINQ expression 'Where( source: DbSet, predicate: (f) => Invoke(__filtering_0, f[DataLog]) )' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
So can you tell me, how I should modify the code to make sure that all (most) of the processing stay on the server side? What is the best practice to keep the generic code yet comply with the standards?