我在SO上已经看到了许多这样的问题,但是这些问题对我没有真正的帮助,所以我决定发布另一个问题,以尝试解决我的问题。
我有一个类14
作为基本GenericRepository<T>
方法的模板,因为我有一个相对较大的模型包,所以我不想为不同的类实现相同的方法一遍又一遍(不要重复自己)。
当我尝试创建用于使用CRUD
进行查询的自定义方法时,出现了问题。
这是我的代码:
Predicate<T>
在我看来,这样做的目的是能够传递任何类型的查询,对其进行评估并作为结果返回。
这是我尝试通过使用名为 public IEnumerable<T> GetMatching(Predicate<T> condition)
=> dbContext.Set<T>.Where(entity => condition(entity));
的字段过滤某些Doctor
对象来获取它们的部分:
EmployeeID
这个想法是,给我一个医生名单,这些医生的Repository.GetMatching(doctor => doctor.EmployeeID > 10);
数字字段大于10。
不幸的是,这给了我以下错误:
EmployeeID
根据错误消息,我尝试在Unhandled exception. System.InvalidOperationException: The LINQ expression 'DbSet<Doctor>
.Where(d => Invoke(__condition_0, d[Doctor]))' 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().
函数的末尾添加ToList()
,但没有发现,它仍然失败,并显示了相同的错误消息。
我想念什么?
答案 0 :(得分:1)
取Predicate
代替Expression<Func<T, bool>>
,然后直接传递给它:
public IEnumerable<T> GetMatching(Expression<Func<T, bool>> condition)
=> dbContext.Set<T>.Where(condition);
这样做的原因是,实体框架依赖于表达式树来确定如何将LINQ代码转换为SQL查询。当它正在评估的表达式(您传递给Where的lambda)调用一个实体框架不知道如何翻译的函数(例如有人传入您的函数的任意委托)时,它就会窒息。
请注意,返回IEnumerable<T>
会使添加到返回值上的所有其他LINQ代码都被视为LINQ-to-Objects,而不是由Entity Framework进行评估,这一点应引起注意。如果您要这样做,请考虑调用.ToList()
并返回类似IReadOnlyCollection<>
的内容,以避免不必要的延迟执行。如果没有,请考虑返回IQueryable<>
。