gpt4 book ai didi

c# - 如何为 EF Core 创建可重用的 'Contains' 表达式

转载 作者:行者123 更新时间:2023-12-04 07:39:02 25 4
gpt4 key购买 nike

问题
我需要通过使用表达式的通用存储库与其他过滤器一起执行部分文本搜索。
当前代码的状态
我有一个从我的数据库返回分页结果的通用方法(通过公共(public)存储库层)。
在以下工作示例中;

  • PagedRequest包含当前页面大小和页码,并在各个 Skip 期间使用/Take操作。
  • PagedResult包含结果的集合,以及记录的总数。

  • public Task<PagedResult<Person>> GetPeopleAsync(PersonSearchParams searchParams,
    PagedRequest pagedRequest = null)
    {
    ParameterExpression argParam = Expression.Parameter(typeof(Locum), "locum");

    // start with a "true" expression so we have an expression to "AndAlso" with
    var alwaysTrue = Expression.Constant(true);
    var expr = Expression.Equal(alwaysTrue, alwaysTrue);

    if (searchParams != null)
    {
    BinaryExpression propExpr;

    if (searchParams.DateOfBirth.HasValue)
    {
    propExpr = GetExpression(searchParams.DateStart,
    nameof(Incident.IncidentDate),
    argParam,
    ExpressionType.GreaterThanOrEqual);

    expr = Expression.AndAlso(expr, propExpr);
    }

    if (searchParams.DateOfDeath.HasValue)
    {
    propExpr = GetExpression(searchParams.DateEnd,
    nameof(Incident.IncidentDate),
    argParam,
    ExpressionType.LessThanOrEqual);

    expr = Expression.AndAlso(expr, propExpr);
    }

    if (searchParams.BranchId.HasValue && searchParams.BranchId.Value != 0)
    {
    propExpr = GetExpression(searchParams.BranchId,
    nameof(Incident.BranchId), argParam);

    expr = Expression.AndAlso(expr, propExpr);
    }
    }

    var lambda = Expression.Lambda<Func<Locum, bool>>(expr, argParam);
    return _unitOfWork.Repository.GetAsync(filter: lambda, pagedRequest: pagedRequest);
    }
    这是使用我的静态 GetExpression Expression.Equal 的方法, Expression.GreaterThanOrEqualExpression.LessThanOrEqual查询如下;
    private static BinaryExpression GetExpression<TValue>(TValue value,
    string propName, ParameterExpression argParam, ExpressionType? exprType = null)
    {
    BinaryExpression propExpr;

    var prop = Expression.Property(argParam, propName);
    var valueConst = Expression.Constant(value, typeof(TValue));

    switch (exprType)
    {
    case ExpressionType.GreaterThanOrEqual:
    propExpr = Expression.GreaterThanOrEqual(prop, valueConst);
    break;
    case ExpressionType.LessThanOrEqual:
    propExpr = Expression.LessThanOrEqual(prop, valueConst);
    break;
    case ExpressionType.Equal:
    default:// assume equality
    propExpr = Expression.Equal(prop, valueConst);
    break;
    }
    return propExpr;
    }
    注意:此代码工作正常。
    问题
    使用其他 SO 答案中的示例,我尝试了以下方法;
    表达式
    我尝试通过 Expression 获取包含;
    static Expression<Func<bool>> GetContainsExpression<T>(string propertyName, 
    string propertyValue)
    {
    var parameterExp = Expression.Parameter(typeof(T), "type");
    var propertyExp = Expression.Property(parameterExp, propertyName);
    MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
    var someValue = Expression.Constant(propertyValue, typeof(string));
    var containsMethodExp = Expression.Call(propertyExp, method, someValue);
    return Expression.Lambda<Func<bool>>(containsMethodExp);
    }
    这必须转换为 BinaryExpression因此可以使用 AndAlso 将其添加到表达式树中.我尝试比较 Expressiontrue值(value),但这不起作用
    if (searchParams.FirstName.IsNotNullOrWhiteSpace())
    {
    var propExpr = GetContainsExpression<Locum>(nameof(Locum.Firstname),
    searchParams.FirstName);

    var binExpr = Expression.MakeBinary(ExpressionType.Equal, propExpr, propExpr);
    expr = Expression.AndAlso(expr, binExpr);
    }
    方法调用表达式
    我还尝试返回 MethodCallExpression (而不是上面的 Lambda),使用以下内容;
    static MethodCallExpression GetContainsMethodCallExpression<T>(string propertyName, 
    string propertyValue)
    {
    var parameterExp = Expression.Parameter(typeof(T), "type");
    var propertyExp = Expression.Property(parameterExp, propertyName);
    MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
    var someValue = Expression.Constant(propertyValue, typeof(string));
    var containsMethodExp = Expression.Call(propertyExp, method, someValue);

    return containsMethodExp;
    }
    我按如下方式使用它;
    if (searchParams.FirstName.IsNotNullOrWhiteSpace())
    {
    var propExpr = GetContainsMethodCallExpression<Person>(nameof(Person.FirstName),
    searchParams.FirstName);

    var binExpr = Expression.MakeBinary(ExpressionType.Equal, propExpr, alwaysTrue);
    expr = Expression.AndAlso(expr, binExpr);
    }
    异常(exception)
    这些表达式被传递给从数据库中分页信息的通用方法,并且在第一次执行查询时,当 I Count the total matching number of record of the构造的 query 时抛出异常.

    System.InvalidOperationException: 'The LINQ expression 'DbSet().Where(p => True && p.FirstName.Contains("123") == True)' 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.'


    此异常在 Count 上引发我在分页代码中使用的方法。此代码已经在没有任何过滤器的情况下工作,并且使用 ExpressionType顶部描述的过滤器,因此我没有包含此代码,因为我认为它不相关。
    pagedResult.RowCount = query.Count();

    最佳答案

    This has to be converted to a BinaryExpression so it can be added to the expression tree using AndAlso


    消极的。没有要求 Expression.AndAlso (或 Expression.OrElse )操作数是二进制表达式(这会很奇怪,就像要求 &&|| 的左或右操作数始终是比较运算符)。唯一的要求是它们是 bool返回表达式,因此调用字符串 Contains是一个完全有效的操作数表达式。
    因此,首先将内部局部变量的类型从 BinaryExpression 更改为至 Expression :
    if (searchParams != null)
    {
    Expression propExpr;

    // ...
    }
    同样的 btw 适用于初始表达式 - 你不需要 true == true , 简单的 Expression expr = Expression.Constant(true);也会这样做。
    现在您可以发出对 string.Contains 的方法调用在与您发布的另一个类似的单独方法中(传递 ParameterExpression 和构建属性选择器表达式)或内联类似于:
    if (searchParams.FirstName.IsNotNullOrWhiteSpace())
    {
    var propExpr = Expression.Property(argParam, nameof(Person.FirstName));
    var valueExpr = Expression.Constant(searchParams.FirstName);
    var containsExpr = Expression.Call(
    propExpr, nameof(string.Contains), Type.EmptyTypes, valueExpr);
    expr = Expression.AndAlso(expr, containsExpr);
    }

    关于c# - 如何为 EF Core 创建可重用的 'Contains' 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67585220/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com