簡體   English   中英

使用表達式樹創建動態LINQ查詢

[英]Creating Dynamic LINQ Queries using Expression Trees

我無法復制多個。在使用表達式樹的linq查詢中,由於該查詢具有搜索功能,因此我需要此查詢是動態的。我將要查詢的數據庫最終會變得很大,所以我需要高效且不能過濾客戶端。 我至少嘗試從這些列中的3個開始過濾。 在下面,我添加了三個我試圖過濾的ID。 我已經讀了很多表達式樹,但是可以使用某人的幫助將它們實際應用到即時通訊中,因為它們使我感到困惑。

    public int? heightId { get; set; }
    public int? ageId { get; set; }
    public int? genderId { get; set; }

它不是動態的,因為您事先知道各列。 您也不需要使用表達式樹。 您可以有條件地應用過濾器:

public Class[] FindByFilter(int limit, int? heightId = null, int? ageId = null, int? genderId = null)
{
    var classes = databaseContext.Set<Class>();

    if (heightId.HasValue)
        classes = classes.Where(c => c.HeightId == heightId.Value);

    if (ageId.HasValue)
        classes = classes.Where(c => c.AgeId == ageId.Value);

    if (heightId.HasValue)
        classes = classes.Where(c => c.GenderId == genderId.Value);    

    return classes.Take(limit).ToArray();
}

因此,現在FindByFilter(10, 1, null, 2)或等效的FindByFilter(10, heightId: 1, genderId: 2)將返回前10行,其高度為1,性別為2,但年齡FindByFilter(10, heightId: 1, genderId: 2)

因此,您有一類(或幾個類)的屬性數量有限,可能少於100。

在代碼中的某個位置,這可能在用戶界面中,但是也可能是在讀取互聯網頁面,文件或從數據庫中獲取信息之后,在代碼中的某個地方,您將有一些輸入,可以從中確定哪些輸入必須在Where執行。

因此,在代碼中的某個地方,您有一個函數,該函數接受一些輸入並返回where的Expression:

Expression<Func<MyTable, bool>> CreateExpression(MyInput input) {...}

問題是,我們不知道您如何獲得輸入。 我們所知道的是,只有有限的(少於前面提到的100)可能的輸出。 如果輸入錯誤,則該過程應將其更正為最佳猜測輸出,或拒絕產生輸出。

無論如何,這個漫長的故事是要告訴您,應該創建表達式的代碼相對有限。 如果您不讓它成為動態的,而是創建一個非動態的函數,即使您有一個帶有50個案例的大switch語句,它也是更好理解, 可測試維護的方式。

例如:假設操作員必須輸入要過濾的屬性的名稱和值。 他可能會輸入錯誤,在這種情況下,您會警告操作員輸入錯誤

Expression<Func<MyTable, bool>> CreateExpression(string input, int value)
{
     // TODO: make the procedure case insensitive
    switch (input)
    {
        case "HeightId":
             return myItem => myItem.HeightId == value;
        case "AgeId":
             return myItem => myItem.AgeId == value;
        ...
        default:
            WarnUserIncorrectInput(...)
            return null;
    }
}

您期望多少宗案件? 即使有20個,與使用某種魔術解釋創建表達式相比,該代碼也更容易理解和檢查錯誤輸入。 畢竟:這種不可思議的解釋還應該檢查輸入是否錯誤。

如果將來要添加或刪除屬性,則維護此功能將相當容易。

復雜的表達

可能是您希望操作員使用某種定義的語言來組合表達式,例如:

"HeightId == 4 AND AgeId == 10 OR ..."

如果您選擇這種投入,將會使您的生活變得非常困難。 為此,您幾乎必須構建某種編譯器,檢查各種錯誤輸入。 您必須檢測出運算符何時表示屬性,何時運算符或比較器。 不容易做到。

如果您確實希望組合表達式,可以考慮使用用戶界面元素(例如組合框),用戶必須在其中選擇屬性,然后鍵入正確的值類型。

由於屬性的數量是有限的,因此可以使用上述過程創建表達式。 合並如下所示:

ExpressionFunc<TSource, bool>> CreateAnd<TSource>(
    Expression<Func<TSource, bool>> X,
    Expression<Func<TSource, bool>> Y)
{
     return (sourceElement) => X(sourceElement) && Y(sourceElement);
}

再說一次:即使您想讓運算符組合語句,如果使用組合框或類似框,也不會得到錯誤的輸入,並且組合的數量也相當有限。

結論

盡管可以從字符串輸入創建表達式,但這意味着您必須創建類似編譯器的工具來檢查錯誤的輸入。 這將不容易理解,測試和維護。

由於請求的Where語句的數量相當有限(可能少於100個),因此請考慮使用一個開關大小的函數

暫無
暫無

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

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