【问题标题】:How to build where predicate in EF Core in which the property selected is dynamic如何在 EF Core 中构建 where 谓词,其中所选属性是动态的
【发布时间】:2022-11-23 07:41:17
【问题描述】:

我正在努力处理表达式树和 Entity Framework Core。

我有一个方法返回我将用于过滤的表达式树,例如:

public Expression<Func<E, bool>> GetWherePredicate<E>(Func<E, NpgsqlTsVector> selector, string queryText) 
{
    return entity => selector(entity).Matches(queryText);
}

然后我想用类似的东西调用这个方法:

 query = query.Where(GetWherePredicate<MyEntity>(i => i.MySearchField, "the_query"));

这会产生一个错误,类似于:

System.InvalidOperationException:LINQ 表达式 'DbSet()
.Where(i => 调用(__selector_0, i)
.Matches(__queryText_1))' 无法翻译。以可翻译的形式重写查询,或通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用显式切换到客户端评估。有关详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2101038

虽然我明白为什么这不起作用,但我不确定如何解决这个问题,但怀疑它与使用表达式树有关。我想创建一个具有以下签名的新函数,例如:

Expression<Func<E, bool>> GetWherePredicate<E>(MemberExpression selectorForSearchField, string queryText);

但我无法弄清楚如何采用该表达式并应用 Matches 函数。

任何帮助表示赞赏。

谢谢, 埃里克

【问题讨论】:

    标签: .net-core entity-framework-core expression-trees npgsql


    【解决方案1】:

    对谓词使用 Expression<Func 模式:

    Expression<Func<TimeAndAttendancePunchIn, bool>> predicate = e => e.EmployeeId == employeeId;
    
    PageListViewContainer<TimeAndAttendancePunchInView> container = await taMod.TimeAndAttendance.Query().GetViewsByPage(predicate, order, pageSize, pageNumber);
    
         public async Task<PageListViewContainer<TimeAndAttendancePunchInView>>  GetViewsByPage(Expression<Func<TimeAndAttendancePunchIn, bool>> predicate, Expression<Func<TimeAndAttendancePunchIn, object>> order, int pageSize, int pageNumber)
        {
    
            var query = _unitOfWork.timeAndAttendanceRepository.GetEntitiesByExpression(predicate);
            query = query.OrderByDescending(order).Select(e => e);
    
            IPagedList<TimeAndAttendancePunchIn> list = await query.ToPagedListAsync(pageNumber, pageSize);
    

    存储库

     public IQueryable<TimeAndAttendancePunchIn> GetEntitiesByExpression(Expression<Func<TimeAndAttendancePunchIn, bool>> predicate)
        {
            var result =  _dbContext.Set<TimeAndAttendancePunchIn>().Where(predicate);
    
            return result;
        }
    

    【讨论】:

      【解决方案2】:

      以下是回答问题的一种方法,但并不像我想的那么简单。或者更准确地说,我的直觉告诉我有一种更干净、更简单的方法。

      我的(不是那么简单)方法如下:

      创建一个采用 MemberExpression 的函数(不是选择属性的函数),如下所示:

          public Expression<Func<E, bool>> GetWherePredicate<E>(
              MemberExpression member, 
              string queryText)
          {
              // Get the parameter from the member
              var parameter = GetParameterExpression(member);
      
              // Convert the query text into a constant expression
              var queryTextExpression = Expression.Constant(queryText, typeof(string));
      
              // Create an expression for the matches function
              ftsMatchesFunction = typeof(NpgsqlFullTextSearchLinqExtensions).GetMethod("Matches",
                          BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
                          null,
                          new[] { typeof(NpgsqlTsVector), typeof(NpgsqlTsQuery) },
                          null);
              var matchesExpression = Expression.Call(ftsMatchesFunction, member, partialSearchExpression);
              return Expression.Lambda<Func<E, bool>>(matchesExpression, parameter);
          }
      
      

      然后添加谓词,我有类似的东西:

              var predicate = PredicateBuilder.New<MyEntity>(false);
      
              var myEntity= Expression.Parameter(typeof(MyEntity), "e");
              var childEntity= Expression.PropertyOrField(myEntity, nameof(Invoice.Child));
              var searchProperty = Expression.PropertyOrField(childEntity, nameof(Child.FtsSearchVector));
      
              predicate = predicate.Or(_context.GetWherePredicate<MyEntity>(
                  searchProperty, 
                  "the_query_text"));
      

      最后将过滤器添加到查询中:

          query = query.Where(predicate);
      

      更清洁或更简单的解决方案是不需要表达式树的解决方案,因为需要表达式树的唯一原因是因为我无法弄清楚如何以 ef 可以理解的方式选择搜索属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-01-14
        • 2023-01-18
        • 1970-01-01
        • 1970-01-01
        • 2022-11-16
        • 2021-04-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多