簡體   English   中英

Linq to Entities,在查詢表達式中注入聯接

[英]Linq to Entities, Inject Join Inside Query Expression

我正在嘗試提高某些LINQ查詢的性能,有一件小事情需要大量改進:聯接。 幾乎我所有的查詢都有一些用於過濾結果的聯接,但未選擇到結果中。 這些過濾條件是可選的...

我今天所擁有的是:

var q = from t1 in context.Set<T1>() 
    where t1.mandatoryfilter >= 0
    select t1;

if (useFilter) 
{
    var q2 = from t1 in q
        from t2 in context.Set<T2>().Where(t2 => t2.fk == t1.pk).DefaultIfEmpty
        where t2.filterProperty == filterValue
        select t1;

    if (useFilter2) 
    {
        [...]

        return q3.ToList();
    }

    return q2.ToList();
} 
else 
{
    if (useFilter2) 
    {
        [...]

        return q2.ToList();
    }

    return q.ToList();
}

這將生成查詢的投影。 並且根據過濾器的復雜性/數量,它會生成越來越多的投影,並且如果我需要組合一些過濾器,則需要嵌套代碼。 結果查詢的大小可能會變得很大,以致無法通過Internet發送(實際上不是太大的XD,但它會導致性能問題),並且代碼本身也很難維護。

我知道我可以改回字符串SQL ...但這不是一個非常優雅的解決方案嗎?

我想知道是否有一種方法可以注入聯接,而過濾器直接執行表達式樹,因此提供程序將不會生成投影,並且代碼將是線性且簡單的。

ps:非常重要的信息,我使用的是EF6,Linq-to-Entities,默認SqlClient。

謝謝大家。

我對LINQ的查詢語法版本不太有把握,並且沒有打開VS,因此我使用方法語法來確保我正確無誤:但是同樣的想法適用。

這是應用過濾器的相當標准的方法。 您不必每次都創建新查詢,只需為每個過濾器附加一個謂詞即可。 也適用於聯接(除非您使用自定義聯接,否則可能無需顯式使用.Join

var people = context.Set<Person>()
                .Where(p => p.mandatoryFilter > 0);

if (filter.WithAddress != null)
    people = people.Where(p => p.Address == filter.WithAddress);

if (filter.WithBossName != null)
    people = people.Where(p => p.Boss.Name == filter.WithBossName);

return people.ToList();

如果使用導航屬性,則幾乎不需要連接,並且可以將大多數過濾條件作為單個表達式應用。

假設您的T1實體具有導航屬性T2 過濾器表達式將如下所示:

q = q.Where(q.T2.filterProperty1 == filterProperty == filterValue);

您還可以在此處看到僅將表達式追加到現有查詢q

現在,它變成一種常用的模式,以向IQueryable添加過濾條件:

IQueryable<T1> query = from t1 in context.Set<T1>() 
                       where t1.mandatoryfilter >= 0
                       select t1;

if (filterValue2 != null)
    query = query.Where(t => t.T2.filterProperty == filterValue2);
if (filterValue3 != null)
    query = query.Where(t => t.T3.filterProperty == filterValue3);
if (filterValue4 != null)
    query = query.Where(t => t.T4.filterProperty == filterValue4);

(請注意, queryIQueryableIQueryable ,否則分配query = query....請勿編譯。)

現在,您甚至可以將過濾器應用於1:n關聯

if (filterValue5 != null)
    query = query.Where(t => t.T5s.Any(t5 => t5.filterProperty == filterValue5));

如果使用join進行過濾,則無法執行此操作,因為它將使結果集相乘。

暫無
暫無

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

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