【问题标题】:How to get dynamic predicate using expressions when joining in Linq加入Linq时如何使用表达式获取动态谓词
【发布时间】:2018-04-26 11:42:49
【问题描述】:

我编写了一个静态方法,它将使用表达式 api 为不同类型的字段提供适当的谓词 lambda。

static Func<T, bool> Process<T>(string type)
{

    ParameterExpression parameter = Expression.Parameter(typeof(T));
    Expression predicate = Expression.Constant(true);
    if (type == "Start")
    {
        Expression prop = Expression.Property(parameter, type);
        Expression filter = Expression.LessThan(prop, Expression.Constant(DateTime.Now));
        predicate = Expression.AndAlso(predicate, filter);
    }
    //TODO: more if statments to come
    var lambda = Expression.Lambda<Func<T, bool>>(predicate, parameter);
    return lambda.Compile();
}

如果我像这样在 linq 中执行单个查询操作,上面的代码可以正常工作:

var del = Process<MyClass>("Start");
var data = DbContext.MyClass.Where(del); //gets the result data

public class MyClass
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public long Id { get; set; }
}

现在,如果我加入 MyClass 实体

var data = DbContext.MyClass
         .Join(DbContext.Detail, mc => mc.Id, detail => detail.Id, (m, d) =>
                     new { m = m, d = d})
         .Where(del);

以上行给出编译时错误

Error   CS1929  'IQueryable<<anonymous type: MyClass m, Detail d>>' does not contain a definition for 'Where' and the best extension method overload 'EnumerableRowCollectionExtensions.Where<MyClass>(EnumerableRowCollection<MyClass>, Func<MyClass, bool>)' requires a receiver of type 'EnumerableRowCollection<MyClass>'

我了解.Where() 现在需要一个具有 md 的匿名类型,但不确定如何解决此问题。

我对 Expression API 还是很陌生。不知道如何实现。

我试图通过创建匿名类型变量来实现这一点,但这是一个变量而不是类型本身,可以将其传递给Process&lt;T&gt;()

【问题讨论】:

  • 在你比较MyClassDateTime的表达式中,这不是一个有效的Func&lt;T,bool&gt;,你只能比较相关/正确的类型,这里你必须使用MyClass的属性构建像 Start / End 这样 DateTime 的 Func

标签: c# linq lambda linq-to-entities expression-trees


【解决方案1】:

Process 方法的结果是Where 子句用于MyClass 类型的对象,因此您不能使用它来过滤匿名对象{ m, d }。而是在Join 之前过滤:

var data = DbContext.MyClass.Where(del);                        
                            .Join(DbContext.Detail,
                                  mc => mc.Id,
                                  detail => detail.Id,
                                  (m, d) => new { m, d }
                             );

【讨论】:

  • 还将Func&lt;T, bool&gt; 更改为Expression&lt;Func&lt;T, bool&gt;&gt; 并将return lambda.Compile(); 更改为return lambda;。否则你所有的努力都将付诸东流,因为查询将在检索整个MyClass 表后在内存中执行。
猜你喜欢
  • 1970-01-01
  • 2010-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多