您的位置:首页 > 编程语言 > C#

[转]C#3.0入门系列(九)-之GroupBy操作

2009-04-02 18:02 513 查看
有朋友反馈说我提供的sample不能编译。大概是版本的问题,可以到http://msdn2.microsoft.com/en-us/bb330936.aspx下载for beta1的版本。本节接着讲groupby。

上一节,我们讲了如何理解groupby返回的结果。本节会延这个思路阐述下去。先来看下面的例子

GroupBy操作中Select的匿名类

var q = from p in db.Products

group p by p.CategoryID into g

select new { CategoryID = g.Key, g };
本例中,select操作中使用了匿名类。本系列中第一次提到匿名类是在/article/4785680.html 一文中。本文将再一次,阐述匿名类的理解。所谓匿名类,其实质,并不是匿名,而是编译器帮你去创建了这么一个类,在用户看来,好像并没有去创建,此所谓匿名类。也就是说,编译器在编译时,还是有这个类的,这个类是编译器自己创建的,其名称是编译器界定的。 在上例的匿名类中,有2个property,一个叫CategoryID, 一个叫g。 大家要注意了,这个匿名类,其实质是对返回结果重新进行了包装。而那个叫做g的property,就封装了一个完整的分组。如图,仔细比较和上篇图的区别。

var q = from p in db.Products

group p by p.CategoryID into g

select new { CategoryID = g.Key,GroupSet = g };
只是把g重新命名为GroupSet.需要用下面的遍历,获取每个产品纪录。

foreach (var gp in q)

SELECT MAX([t0].[UnitPrice]) AS [MaxPrice], [t0].[CategoryID]

FROM [dbo].[Products] AS [t0]

GROUP BY [t0].[CategoryID]
我们来看看,dlinq如何来做同样的事情.如下,先按CategoryID归类,然后,只取CategoryID值和同类产品中单价最大的。

var q =

from p in db.Products

group p by p.CategoryID into g

select new {

g.Key,

MaxPrice = g.Max(p => p.UnitPrice)

};
在这里,Max函数只对每个分组进行操作。我们来看看其结果

var q =

from p in db.Products

group p by p.CategoryID into g

select new {

g.Key,

MinPrice = g.Min(p => p.UnitPrice)

};
每类产品的价格平均值

var q =

from p in db.Products

group p by p.CategoryID into g

select new {

g.Key,

AveragePrice = g.Average(p => p.UnitPrice)

};
每类产品,价格之和

var q =

from p in db.Products

group p by p.CategoryID into g

select new {

g.Key,

TotalPrice = g.Sum(p => p.UnitPrice)

};
各类产品,数量之和

var q =

from p in db.Products

group p by p.CategoryID into g

select new {

g.Key,

NumProducts = g.Count()

};
如果用OrderDetails表做统计,会更好些,因为,不光可以统计同一种产品,还可以统计同一订单。

接着统计,同各类产品中,断货的产品数量。使用下面的语句。

var q =

from p in db.Products

group p by p.CategoryID into g

select new {

g.Key,

NumProducts = g.Count(p => p.Discontinued)

};
在这里,count函数里,使用了Lambda表达式。在上篇中,我们已经阐述了g是一个组的概念。那在该Lambda表达式中的p,就代表这个组里的一个元素或对象,即某一个产品。还可以使用where条件来限制最终筛选结果

var q =

from p in db.Products

group p by p.CategoryID into g

where g.Count() >= 10

select new {

g.Key,

ProductCount = g.Count()

};
这句在翻译成sql语句时,欠套了一层,在最外层加了条件。

SELECT [t1].[CategoryID], [t1].[value2] AS [ProductCount]

FROM (

SELECT COUNT(*) AS [value], COUNT(*) AS [value2], [t0].[CategoryID]

FROM [dbo].[Products] AS [t0]

GROUP BY [t0].[CategoryID]

) AS [t1]

WHERE [t1].[value] >= @p0

-- @p0: Input Int32 (Size = 0; Prec = 0; Scale = 0) [10]

-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 2.0.20612.0
GroupBy操作中GroupBy的匿名类

第一次谈到匿名类时,我们就提到不光Select操作可以使用匿名类,其他操作符也可以。但是,OrderBy不支持。请参考C#3.0入门系列(六)-之OrderBy操作

当用户既想按产品的分类,又想按供应商来做分组,该怎么办呢。这时,我们就该使用匿名类。

var categories =

from p in db.Products

group p by new { p.CategoryID, p.SupplierID } into g

select new {g.Key, g};
在by后面,new出来一个匿名类。这里,Key其实质是一个类的对象,Key包含两个Property,一个是CategoryID,再一个是SupplierID ,要想取到具体CategoryID的值,需要g.Key.CategoryID,才能访问到。我们来看dlinq翻译的T-sql语句。

SELECT [t0].[SupplierID], [t0].[CategoryID]

FROM [dbo].[Products] AS [t0]

GROUP BY [t0].[CategoryID], [t0].[SupplierID]

-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 2.0.20612.0
先按CategoryID,再按SupplierID ,和匿名类中的循序一样。

最后一个例子。

var categories =

from p in db.Products

group p by new { Criterion = p.UnitPrice > 10 } into g

select g;
按产品单价是否大于10分类。其结果为两类,大于的是一类,小于及等于为另一类。好了,剩下的,大家自己多去领会。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: