首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用EF运行包含子查询的动态查询?

如何使用EF运行包含子查询的动态查询?
EN

Stack Overflow用户
提问于 2022-09-12 13:53:53
回答 1查看 119关注 0票数 1

我能够使用except运行各种动态组合查询,除非包含子查询

因此,这不是一个复制的EF核心动态lambda子查询不工作或任何其他我能够找到的事情。

可以在Dotnetfiddle.net/4 4opEqr上找到一个可运行的repro来演示这个问题,它使用一个动态组合的表达式来表示以下查询:

代码语言:javascript
复制
efContext.Products.Where(p => p.Id == efContext.OrderItem.Max(i => i.ProductId)).ToList();

我得到的例外是

代码语言:javascript
复制
System.InvalidOperationException : The LINQ expression 'InternalDbSet<OrderItem> {  }
    .Max(i => i.ProductId)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

我在Microsoft.EntityFrameworkCore.SqlServer中观察到了与Microsoft.EntityFrameworkCore.InMemory相同的行为(版本6.0.8和7.0.0-preview.7.22376.2)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-12 19:36:12

问题似乎既在于EF Core处理表达式树内嵌套可查询表达式的方式,也包括您尝试测试所创建的动态表达式的方式。

很快,这里

代码语言:javascript
复制
productQueryable.Where(p => p.Id == orderItemQueryable.Max(i => i.ProductId))

productQueryable是正则变量( .Where是常规调用),orderItemQueryable是编译器生成的闭包(作为可查询的Where谓词表达式的一部分)。

代码语言:javascript
复制
() => productQueryable.Where(p => p.Id == orderItemQueryable.Max(i => i.ProductId))

它们都是编译器生成的闭包。

因此,EF不能正确处理在“根”查询表达式中包含嵌套可查询变量值的Constant表达式,因此对于子查询,您应该直接传递IQueryable.Expression属性值,或者模拟闭包(而不是常量)表达式。对于根查询,您应该用常量表达式或模拟闭包(但不是直接)包装它。

因为包装可查询变量对这两种情况都有效,所以解决方案是始终将这些变量封装在闭包模拟表达式中。闭包仿真表达式是指包含常量表达式、保存类实例、在类、属性或字段中保存实际变量的表达式。

它可以通过多种方式实现,例如,使用System.Tuple类作为holder:

代码语言:javascript
复制
static Expression MakeClosure<T>(T value)
{
    var closure = new Tuple<T>(value);
    return Expression.Property(Expression.Constant(closure), nameof(closure.Item1));
}

或者真正的编译器生成闭包类实例:

代码语言:javascript
复制
static Expression MakeClosure<T>(T value)
{
    var closure = new { value };
    return Expression.Property(Expression.Constant(closure), nameof(closure.value));
}

或者使用编译器的主体生成包含闭包的lambda表达式:

代码语言:javascript
复制
static Expression MakeClosure<T>(T value)
{
    Expression<Func<T>> lambda = () => value;
    return lambda.Body;
}

最后,在所有情况下,将示例代码更改为

代码语言:javascript
复制
var productQueryableExp = MakeClosure(productQueryable);
var orderItemQueryableExp = MakeClosure(orderItemQueryable);

一切都会如愿以偿。至少有EF核心。您似乎正在使用的另一个库(Remote.Linq)呢?完全不知道(我猜这将是另一个问题)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73690446

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档