使用表达式树查询多个集合

时间:2016-12-02 12:35:35

标签: c# linq entity-framework-core

我有一些由EF Core提供的IQueryable集合,我想使用System.Linq.Expressions for Entity为它们构建一个动态查询,将其转换为SQL。

IQueryable<ADP> collection1 = _context.Adps;
IQueryable<VHStr> collection2 = _context.VHStrParams;

var q = (from ADP a in collection1
        where collection2.Any(p => p.Value.Contains("I") && p.Entid == a.Id)
        select a);

var l = q.ToList();

这正常工作,实体生成正确的SQL。

问题是 - 如何使用表达式构建此类查询?我只是无法弄清楚如何在为第一个元素构建的表达式中访问另一个集合...

编辑:如果有人会找到它,解决方案是:

        IQueryable<ADP> collection1 = _context.Adps;
        IQueryable<VHStr> collection2 = _context.VHStrParams;


        var q = (from ADP a in collection1
                 where collection2.Any(p => p.Value.Contains("I") && p.Entid == a.Id)
                 select a);

        var paramExpA = Expression.Parameter(typeof(ADP), "a");
        var paramExpV = Expression.Parameter(typeof(VHStr), "v");

        var entIdExp = Expression.PropertyOrField(paramExpV, "Entid");
        var adpIdExp = Expression.PropertyOrField(paramExpA, "Id");
        var convertedAdpIdExp = Expression.Convert(adpIdExp, typeof(long?));

        var valueExp = Expression.PropertyOrField(paramExpV, "Value");
        var containsStringMethod = typeof(string).GetMethod("Contains", new[] {typeof(string)});
        var constValueExp = Expression.Constant("I", typeof(string));
        var containsExp = Expression.Call(valueExp, containsStringMethod, constValueExp);

        var equalIdsExp = Expression.Equal(entIdExp, convertedAdpIdExp);
        var andExp = Expression.AndAlso(containsExp, equalIdsExp);

        var lambda1 = Expression.Lambda<Func<VHStr, bool>>(andExp, paramExpV);
        var vhstrAnyMethod =
            typeof(Queryable)
                .GetTypeInfo()
                .GetMethods()
                .First(m => m.Name == "Any" && m.GetParameters().Count() == 2)
                .MakeGenericMethod(typeof(VHStr));

        var collection2ConstExpr = Expression.Constant(collection2);
        var anyCallExp = Expression.Call(vhstrAnyMethod, collection2ConstExpr, lambda1);

        var collection1ConstExpr = Expression.Constant(collection1);
        var lambda2 = Expression.Lambda<Func<ADP, bool>>(anyCallExp, paramExpA);

        var whereExp = Expression.Call(
            typeof(Queryable),
            "Where",
            new Type[] { typeof(ADP) },
            collection1ConstExpr,
            lambda2);

        var lambda3 = Expression.Lambda<Func<IQueryable<ADP>>>(whereExp);
        var resultFunc = lambda3.Compile();
        var resultQuerable = resultFunc();

        var resultList = resultQuerable.ToList();

1 个答案:

答案 0 :(得分:1)

  

我无法弄清楚如何在为第一个元素构建的表达式中访问另一个集合...

好吧,编译时查询使用闭包类将外部变量传递给查询。您可以在手动构建表达式树时执行相同操作,但无需执行此操作,因为您只需使用Expression.Constant方法将变量转换为表达式:

ViewBag