2017-05-27 107 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)) 
相关问题