首页 > 解决方案 > LINQ EF Core 3.0 中的重大更改。使用表达式

问题描述

在我的应用程序中,我有一些使用相同重复逻辑的查询:

var someThings = context.table1
  .where(SomeLogic)
  .ToList();

使用 EF Core 2.1,我可以将此逻辑封装在具有所有这些表达式的层中:

public static Expression<Func<MyObject, bool>> SomeLogic =>
            myObject => myObject.CreationDate.Date == DateTime.Now.Date
                    && (myObject.Whatever.HasValue || myObject.MoreWhatever);

现在我发现这是在记忆中评估的,这很糟糕。

如果我这样做:

var someThings = context.table1
  .where(myObject => 
      myObject.CreationDate.Date == DateTime.Now.Date
      && (myObject.Whatever.HasValue || myObject.MoreWhatever))
  .ToList();

然后在数据库中评估查询,但我将一些逻辑放在错误的层中。

我试图Expression用一个函数或任何其他工具代替,但我没有找到办法。

有没有办法像我以前一样将查询的逻辑封装在一个层中,但保留 EF 规则以便仍然可以在数据库中评估该查询?

谢谢。

标签: linq.net-coreentity-framework-core.net-core-3.0entity-framework-core-3.0

解决方案


这个答案解释了为什么你需要一个“真实的”表达式而不仅仅是一个 Lambda 。创建的表达式可以在任何地方创建并作为参数传递给执行查询的函数。

这个答案应该指导你需要走的路。你只需要用whatever.hasvalue...stuff替换这两个虚拟表达式

var param = Expression.Parameter(typeof(MyObject), nameof(MyObject));

//    myObject.CreationDate.Date == DateTime.Now.Date
Expression dateExpression = Expression.Equal(Expression.Constant(DateTime.Now),
    Expression.PropertyOrField(param, "CreationDate"));


var dummyExpression1 = Expression.Equal(Expression.Constant(1), Expression.Constant(1));
var dummyExpression2 = Expression.Equal(Expression.Constant(1), Expression.Constant(1));

//    && (myObject.Whatever.HasValue || myObject.MoreWhatever)
Expression orExpression = Expression.Or(dummyExpression1, dummyExpression2);


Expression allConditions = Expression.And(dateExpression, orExpression);

//myObject =>
Expression myExpression = Expression.Lambda<Func<MyObject, bool>>(allConditions, param);

var someThings = context.table1
    .where(myExpression)
    .ToList();

Expression.PropertyOrField 给我带来了最大的麻烦。如果您有嵌套结构,则需要遍历数据结构并调用 Expression.PropertyOrField,第一个参数是上一次调用 Expression.PropertyOrField 的结果。


推荐阅读