首页 > 解决方案 > Entity Framework Core 3.1.6 的动态查询构建问题

问题描述

我正在动态构建 LINQ 查询。我使用 EF Core 3.1.6(用于 SQL Server)。

我使用谓词创建了一个IQueryable带有where()子句的子句。

EF Core 能够翻译以下谓词表达式,并且查询按预期工作:

{p => ((p.Address != null) AndAlso p.Address.Contains(Convert("6152 Fames Ro", String)))}

但 EF Core 无法翻译以下谓词表达式:

{p => (((p.FirstName != null) AndAlso p.FirstName.Contains(Convert("fred", String))) OrElse ((p.MiddleName != null) AndAlso p.MiddleName.Contains(Convert("fred", String))))}

它抛出以下异常:

LINQ 表达式 'DbSet\r\n .Where(p => p.FirstName != null && p.FirstName.Contains("fred") || p.MiddleName != null && p.MiddleName.Contains("fred" ))' 无法翻译。以可翻译的形式重写查询,或通过插入对 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync() 的调用显式切换到客户端评估。有关详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2101038

我调查了以下问题:

正如异常消息中所建议的,我尝试在决赛中做等AsEnumerable(),但没有奏效。我想这将排除客户评估问题。ToList()IQueryable

我确信我做错了什么;不知道是什么。

有人可以帮忙吗?如果需要,我可以提供更多信息。

标签: c#entity-frameworklinqpredicatebuilder

解决方案


我找到了解决我的问题的方法。

谓词应按如下方式构造:

{p => (((p.FirstName != null) AndAlso p.FirstName.Contains(Convert("fred", String))) OrElse Invoke(p => ((p.MiddleName != null) AndAlso p.MiddleName.Contains(Convert("fred", String))), p))}

上述谓词工作正常。

为了解决这个问题,我做了 2 处更改:

  1. 从此转换以下扩展方法:
    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
            Expression<Func<T, bool>> expr2)
        {
            return Expression.Lambda<Func<T, bool>>
                (Expression.OrElse(expr1.Body, expr2.Body), expr1.Parameters);
        }
    
    对此:
    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
            Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters);
            return Expression.Lambda<Func<T, bool>>
                (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
        }
    
  2. 改变了方式,我由此构造了常量表达式:
    var member = Expression.Property(parameter, propertyInfo);
                var filterValueConstant = Expression.Convert(Expression.Constant(convertedValue), propertyType);
    
    对此:
    var underlyingTypeConstExpr = Expression.Constant(convertedValue);
                var filterValueConstant = Expression.Convert(underlyingTypeConstExpr, propertyType);
    

这解决了我的问题。但我仍然不知道为什么旧谓词不起作用。


推荐阅读