c# - 用表达式树查询多个集合

标签 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();

最佳答案

I just can't figure out how can I access another collection in the expressions built for elements of the first one...

好吧,编译时查询使用闭包类将外部变量传递给查询。您可以在手动构建表达式树时执行相同的操作,但没有必要这样做,因为您可以简单地使用 Expression.Constant。将变量转换为表达式的方法:

var collection2expr = Expression.Constant(collection2);
var anyParam = Expression.Parameter(collection2.ElementType, "p");
var anyPredicate = Expression.Lambda(
    dynamically_built_predicate_body, // p.Value.Contains("I") && p.Entid == a.Id
    anyParam);
var anyCall = Expression.Call(
    typeof(Queryable), "Any", new Type[] { anyParam.Type },
    collection2Expr, Expression.Quote(anyPredicate));
// etc...

关于c# - 用表达式树查询多个集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40932400/

相关文章:

entity-framework-core - EF CORE如何将NVARCHAR转为VARCHAR

c# - 如何在 .NET 枚举中搜索正确的方法

c# - 绑定(bind) WebGrid 表单 AJAX

c# - 是否可以在不求助于动态 SQL 的情况下查询用户指定的列名?

Linq 查询,如何从单个表构建嵌套对象

c# - 如果字符串包含子字符串,则从 String 数组中获取整个字符串

c# - 使用 EntityFramework Core 为包含大量信息的数据播种的最佳方法是什么?

c# - 具有 Entity Framework Core 2.0 的多个子实体中的相同属性名称

c# - 将 SSL 添加到 TcpListen 服务器?

C# 比较 4 个字符串数组