【发布时间】:2020-02-27 07:12:36
【问题描述】:
我正在尝试使用这个表达式 (dbIdGetter):
f => f.FormTemplateId
并在“包含”表达式中使用它:
IEnumerable<ApiEntity> batch = apiEntities.Take(batchSize);
IEnumerable<IdType> batchIds = batch.Select(apiIdGetterCompiled).ToList();
var parameter = Expression.Parameter(typeof(DbEntity), "f");
var batchIdsConst = Expression.Constant(batchIds);
var containsMethod = typeof(List<IdType>).GetMethods().FirstOrDefault(y => y.Name == "Contains");
var body = Expression.Call(Expression.Constant(batchIds), containsMethod, dbIdGetter.Body);
var expr = Expression.Lambda<Func<DbEntity, bool>>(
body,
parameter
);
// Retrieve all the ApiEntity that already exist inside the db to update
IEnumerable<DbEntity> dbBatch = await dbSet.Where(expr).ToListAsync();
“expr”有一个调试字符串:
{f => value(System.Collections.Generic.List`1[System.Int32]).Contains(f.FormTemplateId)}
这个电话:
IEnumerable<DbEntity> dbBatch = await dbSet.Where(expr).ToListAsync();
这个错误:
System.InvalidOperationException: 'The LINQ expression 'DbSet<SomeClass>
.Where(f => List<int> { 2406369, 2487609, 1997152, 1781014, 2239271, 2256035, 2256334, 2360990, 2256541, 2256652, 2360051, 2256568, 2256600, 2256482, 2256057, 2256088, 2239292, 1934309, }.Contains(f.FormTemplateId))'
我做错了什么?
【问题讨论】:
-
现在无法检查,但使用带有新参数的 lambda body 看起来很可疑。值得一试
var parameter = dbIdGetter.Parameters[0]; -
你是我的英雄,就是这样。谢谢你。如果我有比这更动态的情况,我将不得不使用 ExpressionVisitor 来确保所有参数都通过引用相同?
-
确实如此。我通常使用像这样的小参数替换助手stackoverflow.com/questions/51497089/…
-
这是一个经典问题。是的,参数对象在表达式树中通过引用进行比较。 C# 不允许嵌套的 lambda 在其参数名称中发生冲突,但表达式树库允许,并且引用相等可让您在冲突参数之间消除歧义,而无需强加可能不是您想要的范围规则。不幸的是,鉴于 C# 3 的日程安排非常紧张,我无法提出一个好的诊断机制来检测这个常见错误。
标签: c# linq-expressions ef-core-3.1