Entity Framework 4 in Action读书笔记——第四章:使用LINQ to Entities查询:分组数据

4.3 分组数据

基本需求:根据送货城市分组返回所有订单。

解决方案:在查询中使用group ... by ...子句。

var result = from c in ctx.Orders
             group c by c.ShippingAddress.City;

结果类型有点复杂,因为它是IEnumerable<IGrouping<string, Order>>的对象。IGrouping是一个特殊的类,它有一个键(Key)属性,在本例中是送货地址的值,和一个值(Value)属性。值属性是一个IEnumerable<T>集合,它包含对应Key的所有对象。例如,如果Key属性的值是Miami,Value属性包含所有送货地址是这个城市的订单。

遍历这个结果需要一个对所有Key的循环和一个内循环,内循环遍历对应Key的值。

foreach (var key in result)
            {
                Console.WriteLine(key.Key);
                foreach (var item in key)
                {
                    Console.WriteLine(item.OrderId);
                }
            }

下面更改分组数据的名称。

var result = from c in ctx.Orders
             group c by c.ShippingAddress.City into oGroup
             select new { CityName = oGroup.Key, Items = oGroup };
foreach (var key in result)
{
    Console.WriteLine(key.CityName);
    foreach (var item in key.Items)
    {
        Console.WriteLine(item.OrderId);
    }
}

前面已经提到分组键,但是我们没有解释分组键可以是什么。到目前为止,已经使用了单一的属性,但那只是可能性之一。通常,你要根据多个属性分组数据。例如,你可能想根据送货城市和邮政编码分组订单,以便更好的组织发货。在C#中,你必须使用匿名类型指定一个对象作为键,把送货城市和邮政编码放入其中。下面的代码使用了多个属性分组数据。

var result = from c in ctx.Orders
             group c by new
             {
                 c.ShippingAddress.City,
                 c.ShippingAddress.ZipCode
             };
foreach (var key in result)
{
    Console.WriteLine(key.Key.City + "-" + key.Key.ZipCode);
    foreach (var item in key)
    {
        Console.WriteLine(item.OrderId);
    }
}

正如可以自定义键值以反映你的需求,分组数据也可以使用投影以节省资源。你可以在分组的Select方法内的值列表中调用Select方法,如下:

var result = from c in ctx.Orders
             group c by c.ShippingAddress.City into g
             select new
             {
                 g.Key,
                 Items = g.Select(og => new { og.OrderId, og.OrderDate })
             };

投影的力量还可以允许分组数据包含关联实体的信息。在这里就不展示如何做了,因为它跟上一篇中的相似。

LINQ to Entities甚至可以筛选分组后的数据。这就是接下来的主题。

4.3.1筛选汇总数据

筛选汇总数据等价于在SQL中使用HAVING。举个例子,你可能想搜索按城市分组的订单,订单总数高于一个给定的数字。使用LINQ聚集家族的方法很容易就可以实现这一功能。

var result = from c in ctx.Orders
             group c by c.ShippingAddress.City into g
             where g.Count() > 2
             select g;

分组后面的Where子句只影响分组后的数据。如果你需要在分组之前筛选,你必须在分组之前调用Where。根据Where子句放置的位置,查询中的变量可超出范围。我们修改一下上一段代码。如果你把Where放在group by子句之前,c变量在范围之内,但是g变量不在范围之内,因为还没有声明g。相反,如果把Where子句放在group by子句之后,c变量将不在范围之内,不能被引用,而g变量在范围之内,可以使用。

现在你已经掌握了筛选,投影和分组,下面将学习LINQ to Entities的另一个功能:sorting。它是由LINQ to Entities启用的最简单的任务。当涉及到关联时情况可能有些复杂,但现在你应该感到舒服。

posted @ 2011-09-02 20:04  BobTian  阅读(4473)  评论(16编辑  收藏  举报