簡體   English   中英

Linq2SQL在同一查詢中進行分組和取消分組

[英]Linq2SQL grouping and ungrouping in the same query

這是LINQ to SQL中的一個絆腳石:

string p = prefix ?? "";
string d = delimiter ?? "";
var filegroups = from b in folder.GetFiles(data)
                    where b.Uri.StartsWith(p) && b.Uri.CompareTo(marker ?? "") >= 0
                    group b by data.DataContext.GetFileFolder(p, d, b.Uri);
//var folders = from g in filegroups where g.Key.Length > 0 select g;
//var files = from g in filegroups where g.Key.Length == 0 select g;
var files = filegroups.SelectMany(g => g.Key.Length > 0
    ? from b in g.Take(1) select new FilePrefix { Name = g.Key }
    : from b in g select new FilePrefix { Name = b.Uri, Original = b });

var retval = files.Take(maxresults);

文件夾不能嵌套(在我的控制范圍之內),但文件名可以包含斜杠等,因此可以模擬更深的文件夾結構

folder.GetFiles是一個簡單的linq等效項(IOrderedQueryable),用於select * from files where folderid=@folderid order by Uri

prefix是一個過濾器,它僅返回以...開頭的文件。
定界符是路徑定界符,例如'/'
標記用於分頁-在指定點開始返回

data.DataContext.GetFileFolder映射到sql標量函數:返回整個字符串,直到並包括出現在前綴字符串RETURN substring(@uri, 0, charindex(@delimiter, @uri, len(@prefix)) + len(@delimiter))之后的下一個分隔符RETURN substring(@uri, 0, charindex(@delimiter, @uri, len(@prefix)) + len(@delimiter))這是為了進行故障排除-原來是客戶端的where子句,它確實映射到了TSQL。 我只是希望做一個函數會改變最終圖中的東西,但是不行。

在上面,文件組,注釋掉的文件夾和文件都按預期工作

目標是只打一次數據庫。 我想在一次返回中根據FilePrefix對象的解釋顯示子文件夾和文件(文件夾具有空的“原始”值)

問題在於最終的selectmany拋出“無法格式化節點'ClientQuery'以執行為SQL”。

我強烈懷疑,如果不是針對TSQL轉換的話,這會完美地工作,但是從邏輯上來看,為什么它不執行其數據庫工作,然后選擇FilePrefixes客戶端作為最后一步?

已經很晚了;)但是明天我將通過滑動ToList()或類似的東西在數據庫上雙擊,以使最后一步成為完整的客戶端(合並)。 但是,如果有人對如何通過一個數據庫命中(不編寫存儲過程)來實現這一目標有任何見識,我很樂意聽到!

不利的一面是,如果數據庫命中導致許多記錄遠遠超過該記錄,則最終Take(maxresults)可能會很昂貴。 而我隨后未引用的Skip(maxresults).Take(1)用於標記下一頁)會造成兩倍的傷害。

非常感謝你

Welp,看來需要兩次數據庫匹配。 首先,我注意到調用圖將三級運算符轉換為IIF,這使我認為,在sql方面,IIF可能不喜歡將子查詢作為參數。

string p = prefix ?? "";
string d = delimiter ?? "";
var filegroups = from b in folder.GetFiles(data)
                    where b.Uri.StartsWith(p) && b.Uri.CompareTo(marker ?? "") >= 0
                    group b by data.DataContext.nx_GetFileFolder(p, d, b.Uri);
var folders = from g in filegroups where g.Key.Length > 0 select g.Key;
var files = from b in folder.GetFiles(data)
            where b.Uri.StartsWith(p) && b.Uri.CompareTo(marker ?? "") >= 0
                && data.DataContext.nx_GetFileFolder(p, d, b.Uri).Length == 0
            select b;

folders = folders.OrderBy(f => f).Take(maxresults + 1);
files = files.OrderBy(f => f.Uri).Take(maxresults + 1);

var retval = folders.AsEnumerable().Select(f => new FilePrefix { Name = f })
            .Concat(files.AsEnumerable().Select(f => new FilePrefix { Name = f.Uri, Original = f }))
            .OrderBy(b => b.Name).Take(maxresults + 1);

int count = 0;
foreach (var bp in retval)
{
    if (count++ < maxresults)
        yield return bp;
    else
        newmarker.Name = bp.Name;
}
yield break;

不太優雅...我離開了文件組和文件夾,但是重寫了文件查詢以擺脫該組(生成更干凈的sql,可能更高效)。

Concat在使用這種新方法時仍然給我帶來了麻煩,因此我開始進行AsEnumerable調用,這一點將其分為對數據庫的兩次匹配。

我將maxresults保留在sql中以限制流量,因此最壞的情況是數據傳輸量是我想要的兩倍。 +1是獲取下一條記錄,以便可以通知用戶從下一頁開始的位置。 而且我使用了迭代器模式,因此無需再次循環即可獲得下一條記錄。

暫無
暫無

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

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