亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

不支持客戶端 GroupBy

不支持客戶端 GroupBy

PHP
慕婉清6462132 2024-01-20 15:41:03
我有以下 Entity Framework Core 3.0 查詢:var units = await context.Units  .SelectMany(y => y.UnitsI18N)  .OrderBy(y => y.Name)  .GroupBy(y => y.LanguageCode)  .ToDictionaryAsync(y => y.Key, y => y.Select(z => z.Name));我收到以下錯誤:Client side GroupBy is not supported.要在客戶端或客戶端的一部分上運行查詢,我將執行以下操作:var units = context.Units  .SelectMany(y => y.UnitsI18N)  .OrderBy(y => y.Name)  .AsEnumerable()  .GroupBy(y => y.LanguageCode)  .ToDictionary(y => y.Key, y => y.Select(z => z.Name));現在可以了。如果我沒有在客戶端上運行查詢,為什么會收到此錯誤?
查看完整描述

6 回答

?
慕俠2389804

TA貢獻1719條經驗 獲得超6個贊

GroupBy對于 LINQ 的作用和 SQL 的功能GROUP BY似乎存在一個常見的誤解。由于我陷入了完全相同的陷阱并且最近不得不思考這個問題,因此我決定對這個問題寫一個更徹底的解釋。


簡短回答:

LINQ與 SQL語句GroupBy很大不同GROUP BY:LINQ 只是根據鍵將底層集合劃分為塊,而 SQL 還應用聚合函數將每個塊壓縮為單個值。

這就是 EF 必須在內存中執行 LINQ 類型的原因GroupBy。

在 EF Core 3.0 之前,這是隱式完成的,因此 EF 下載所有結果行,然后應用 LINQ?GroupBy。然而,這種隱式行為可能會讓程序員期望整個LINQ查詢都是在 SQL 中執行的,當結果集相當大時,可能會產生巨大的性能影響。因此,在 EF Core 3.0 中完全禁用了GroupBy隱式客戶端評估。

現在需要顯式調用類似.AsEnumerable()or 的函數.ToList(),該函數下載結果集并繼續內存中的 LINQ 操作。


長答案:

下表solvedExercises將是該答案的運行示例:

+-----------+------------+

| StudentId | ExerciseId |

+-----------+------------+

|? ? ? ? ?1 |? ? ? ? ? 1 |

|? ? ? ? ?1 |? ? ? ? ? 2 |

|? ? ? ? ?2 |? ? ? ? ? 2 |

|? ? ? ? ?3 |? ? ? ? ? 1 |

|? ? ? ? ?3 |? ? ? ? ? 2 |

|? ? ? ? ?3 |? ? ? ? ? 3 |

+-----------+------------+

X | Y該表中的一條記錄表示該學生X已解決習題Y

GroupBy在該問題中,描述了LINQ 方法的常見用例:獲取一個集合并將其分組為塊,其中每個塊中的行共享一個公共鍵。

在我們的示例中,我們可能想要獲得一個Dictionary<int, List<int>>,其中包含每個學生已解決的練習的列表。使用 LINQ,這非常簡單:

var?result?=?solvedExercises
????.GroupBy(e?=>?e.StudentId)
????.ToDictionary(e?=>?e.Key,?e?=>?e.Select(e2?=>?e2.ExerciseId).ToList());

輸出(完整代碼請參見dotnetfiddle):

Student?#1:?1?2?
Student?#2:?2?
Student?#3:?1?2?3

這很容易用 C# 數據類型來表示,因為我們可以嵌套List,并且可以嵌套Dictionary到任意深度。

現在我們嘗試將其想象為 SQL 查詢結果。SQL查詢結果通常表示為一個表,我們可以在其中自由選擇返回的列。為了將上面的查詢表示為 SQL 查詢結果,我們需要

  • 生成多個結果表,

  • 將分組的行放入數組中或

  • 以某種方式插入“結果集分隔符”。

據我所知,這些方法都沒有在實踐中得到實施。最多,有一些像 MySQL 那樣的 hacky 解決方法GROUP_CONCAT,它允許將結果行組合成一個字符串。

因此我們看到,SQL無法產生與 LINQ 概念相匹配的結果GroupBy

相反,SQL 只允許所謂的聚合:例如,如果我們想要計算學生通過了多少練習,我們會寫

SELECT?StudentId,COUNT(ExerciseId)
FROM?solvedExercises
GROUP?BY?StudentId

...這將產生

+-----------+-------------------+
|?StudentId?|?COUNT(ExerciseId)?|
+-----------+-------------------+
|?????????1?|?????????????????2?|
|?????????2?|?????????????????1?|
|?????????3?|?????????????????3?|
+-----------+-------------------+

聚合函數將一組行減少為單個值,通常是標量。示例包括行計數、總和、最大值、最小值和平均值。

由 EF Core 實現的:執行

var?result?=?solvedExercises
????.GroupBy(e?=>?e.StudentId)
????.Select(e?=>?new?{?e.Key,?Count?=?e.Count()?})
????.ToDictionary(e?=>?e.Key,?e?=>?e.Count);

生成上述 SQL。請注意Select,它告訴 EF 應該使用哪個聚合函數來生成 SQL 查詢。


總之,LINQGroupBy函數比 SQL 語句通用得多GROUP BY,由于 SQL 的限制,LINQ 函數只允許返回單個二維結果表。因此,在下載 SQL 結果集之后,必須在內存中評估問題中的查詢和此答案中的第一個示例之類的查詢。

在 EF Core 3.0 中,開發人員選擇在這種情況下拋出異常,而不是隱式執行此操作;這可以防止意外下載包含數百萬行的整個、可能很大的表,而由于測試數據庫較小,這在開發過程中可能會被忽視。


查看完整回答
反對 回復 2024-01-20
?
翻翻過去那場雪

TA貢獻2065條經驗 獲得超14個贊

您的.GroupBy(y => y.LanguageCode).ToDictionaryAsync(y => y.Key, y => y.Select(z => z.Name));無法轉換為 SQL。EF Core 3.0 將拋出異常,以確保您知道Units在分組之前將從數據庫中獲取所有記錄并將其映射到字典。

這是 EF Core 3.0 中最重大的重大變化。


查看完整回答
反對 回復 2024-01-20
?
楊魅力

TA貢獻1811條經驗 獲得超6個贊

GroupBy一種可能的解決方案(對我有用)是在一個對象上制作List。

var units = (
  await context.Units
  .SelectMany(y => y.UnitsI18N)
  .GroupBy(y => y.LanguageCode)
  .ToDictionaryAsync(y => y.Key, y => y.Select(z => z.Name))
  ).ToList().OrderBy(y => y.Name);


查看完整回答
反對 回復 2024-01-20
?
德瑪西亞99

TA貢獻1770條經驗 獲得超3個贊

支持客戶端分組依據

使用 EF Core 3.1.15.0 進行測試

以下代碼返回Client side GroupBy is not supported.錯誤:

MyEntity
????.GroupBy(x?=>?x.MyProperty)
????.ToDictionaryAsync(x?=>?x.Key,?x?=>?x.Count())
????.Dump();

.Select()但由于某種原因,您可以在 后面添加.GroupBy(),它會編譯并運行預期的 SQL:

MyEntity
????.GroupBy(x?=>?x.MyProperty)
????.Select(g?=>?new?{?Key?=?g.Key,?Count?=?g.Count()?})
????.ToDictionaryAsync(x?=>?x.Key,?x?=>?x.Count)
????.Dump();

編譯為:

SELECT?[t].[MyProperty]?AS?[Key],?COUNT(*)?AS?[Count]
FROM?[dbo].[MyEntity]?AS?[t]
GROUP?BY?[t].[MyProperty]
查看完整回答
反對 回復 2024-01-20
?
繁星淼淼

TA貢獻1775條經驗 獲得超11個贊

var test = unitOfWork.PostCategory.GetAll().Include(u=>u.category).GroupBy(g => g.category.name).Select(s => new

                {


                    name = s.Key,

                    count = s.Count()


                }).OrderBy(o=>o.count).ToList();

你可以嘗試這個代碼部分...它會起作用..我已經嘗試過了


查看完整回答
反對 回復 2024-01-20
?
牛魔王的故事

TA貢獻1830條經驗 獲得超3個贊

linq GroupBy 方法可以完成數據庫查詢無法完成的任務。這就是 linq 拋出異常的原因。這并不是一個缺失的功能,但在舊版本的 linq 中,它只是枚舉整個表,然后在本地運行 GroupBy。


Linq 查詢語法恰好有一個group可以轉換為數據庫查詢的關鍵字。


以下是如何使用查詢語法在數據庫上運行查詢的主要工作示例:


var kvPairs = from y in context.Units

              from u in y.UnitsI18N

              orderby u.Name

              group u by u.LanguageCode into g

              select new KeyValuePair<string,IEnumerable<string>>(g.Key, g.Select(z => z.Name));


return new Dictionary<string,IEnumerable<string>>>(kvPairs);

有關詳細信息,請參閱 Microsoft 的這篇文章:https://learn.microsoft.com/en-us/ef/core/querying/complex-query-operators#groupby


查看完整回答
反對 回復 2024-01-20
  • 6 回答
  • 0 關注
  • 274 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號