2017-05-27 38 views
1

由於IQueryable的<產品>與數據庫中的以下值(值是假的,以及作爲一個實體和字段的名稱):的LINQ得到不同的有序元素沒有.GroupBy()

Id  | CategoryName | Price 
------ | -------------|------- 
1  | car   | 10000 
2  | boat   | 15000 
3  | boat   | 20000 
4  | car   | 5000 
5  | boat   | 30000 
6  | food   | 100 
7  | car   | 15000 
8  | food   | 200 

我需要將此IQueryable <產品>轉換爲IOrderedQueryable <產品>,它們的類別中最昂貴的產品的值按價格降序排列。因此,它可能看起來像:

Id  | CategoryName | Price 
------ | -------------|------- 
5  | boat   | 30000 
7  | car   | 15000 
8  | food   | 200 

由於IQueryable的給予執行分組和潛在的SQL查詢排序的能力(和真實表包含關於如何組值進行排序更復雜的規定 - 約10K的行);我想在這裏得到的關鍵是性能

我已經有它看起來像一個有效的解決方案:

IQueryable<Product> queryable = ...; 
var result = queryable 
    .GroupBy(
     x => x.CategoryName, 
     (_, productsInGroup) => productsInGroup 
      .FirstOrDefault(x => x.Price == productsInGroup.Max(p => p.Price)) 
    .OrderByDescending(x => x.Price); 

此解決方案的結果與GROUP BY和嵌套選擇(計算MAX(p.Price)長查詢,選擇正確的行一組等)

有沒有沒有GroupBy做到這一點的能力? 我想有這樣的:

var result = queryable 
    .OrderByDescending(x => x.Price) 
    .ExcludeRowsWithDuplicateCategoryName(); // Distinct by predicate 

讓這樣的查詢將首先以降序排列值:

Id  | CategoryName | Price 
------ | -------------|------- 
5  | boat   | 30000 
3  | boat   | 20000 
7  | car   | 15000 
2  | boat   | 15000 
1  | car   | 10000 
4  | car   | 5000 
8  | food   | 200 
6  | food   | 100 

,然後就莫名其妙地排除行3,2,1, 4,6,因爲它們的CategoryName已經存在於上面的行中。

我該怎麼做?

+0

GROUP BY有什麼問題?您的查詢需要多長時間?你分析了SQL分析器中的查詢並添加了合適的索引嗎? 10k行很小。如果你願意,將它們全部讀入內存。 – Phil

+0

由於這是您需要查詢的實體,所以您需要將查詢轉換爲按價格 – user6144226

+0

@Phil命令分類的RANK/ROW_NUMBER,現在需要1.5-2秒來執行分頁查詢(跳過一些行,取另一行) 。在此示例中以* Price *表示的值是通過使用其他幾個表的複雜規則計算的,而CategoryName實際上是相關表中的一列。有些索引存在,但說實話,我沒有使用SQL分析器。我想,它可以提高性能。 –

回答

1

從我可以告訴在後查詢: 首先找到價格最高的一組

productsInGroup.Max(p => p.Price) 

然後找到與價格匹配的第一個元素英寸

FirstOrDefault(x => x.Price == productsInGroup.Max(p => p.Price)) 

不確定您是否可以實際跳過羣組,但在按價格排序後從羣組中取第一個元素可能會更簡單。

var result = Products.GroupBy(f => f.CategoryName).Select(gr => gr.OrderByDescending(p => p.Price).First()); 
2

這使我心中唯一的選擇是使用自抗加入有比較條件(或NOT EXISTS基於查詢)是這樣的:

var result = queryable 
    .Where(x => !queryable.Any(y => y.CategoryName == x.CategoryName && y.Price > x.Price)) 
    .OrderByDescending(x => x.Price) 
    .ToList(); 

無論是更好的性能,取決於具體的可查詢和數據庫表索引。

值得一提的是,上面的是不完全等效,因爲它會返回一個以上的創紀錄的類別,如果有,每組最多的價格兩種或多種元素,所以完全等效需要附加條件,如:

y => y.CategoryName == x.CategoryName && 
    (y.Price > x.Price || (y.Price == x.Price && y.Id > x.Id))