簡體   English   中英

如何在 EF Core 中構建 where 謂詞,其中所選屬性是動態的

[英]How to build where predicate in EF Core in which the property selected is dynamic

我正在努力處理表達式樹和 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

雖然我明白為什么這不起作用,但我不確定如何解決這個問題,但懷疑它與使用表達式樹有關。 我想創建一個具有以下簽名的新 function,例如:

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

但我無法弄清楚如何采用該表達式並應用Matches項 function。

任何幫助表示贊賞。

謝謝,埃里克

以下是回答問題的一種方法,但並不像我想的那么簡單。 或者更准確地說,我的直覺告訴我有一種更干凈、更簡單的方法。

我的(不是那么簡單)方法如下:

創建一個采用 MemberExpression 的 function(不是選擇屬性的 function),如下所示:

    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 可以理解的方式 select 搜索屬性。

如何使用謂詞創建用於從列表中檢索對象的表達式。

方法一

使用 Predicate<generic> 類型和 IEnumerable

[Fact]
public async Task TestPredicate()
        {
            List<Product> products = new List<Product>
            {
                new Product {ProductID=1,Name="Kayak",Category="Watersports",Price=275m},
                new Product {ProductID=2,Name="Lifejacket", Category="Watersports",Price=48.95m},
                new Product {ProductID=3,Name="Soccer Ball", Category="Soccer",Price=19.50m},
                new Product {ProductID=4,Name="Corner Flag", Category="Soccer",Price=34.95m}
            };

            Predicate<Product> predicate = x => x.ProductID==4;

            var query=Enumerable.FirstOrDefault(products,x=>predicate(x));

            if (query != null) { 
                output.WriteLine(query.Name);
                Assert.True(true);
            }

        }

方法二

對謂詞使用 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;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM