我有一些由 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/