LINQ学习笔记:选取Select(2)

http://www.itjxue.com  2015-07-17 01:59  来源:未知  点击次数: 

LINQ to SQL当中的子查询和连接

子查询在LINQ to SQL当中同样可以很好的工作,他们可以被用于SQL风格的连接查询.以下的例子查询客户的名称以及它对应的采购订单:

   1: var query =
   2:  
   3:   from c in dataContext.Customers
   4:  
   5:   select new
   6:  
   7:   {
   8:  
   9:   c.Name,
  10:  
  11:   Purchases =
  12:  
  13:     from p in dataContext.Purchases
  14:  
  15:     where p.CustomerID == c.ID && p.Price > 1000
  16:  
  17:     select new { p.Description, p.Price }
  18:  
  19:   };

 

此查询匹配了来自两个不同集合的对象,可以想象为是”join”.与传统的数据库连接不同的是它并不会将结果集转换为一个扁平的二维数组,而是将关系型数据映射到一个层级数据对象上.

以下是一个利用Customer上的Purchase关联属性的查询,结果与上述的例子一致,但语法则更加简要一点:

   1: from c in dataContext.Customers
   2:  
   3: select new
   4:  
   5: {
   6:  
   7:   c.Name,
   8:  
   9:   Purchases = from p in c.Purchases
  10:  
  11:               where p.Price > 1000
  12:  
  13:               select new { p.Description, p.Price }
  14:  
  15:   };

 

两个查询都是类似于SQL当中的LEFT OUT JOIN,即我们将选择所有的客户列表,即使他们没有任何的采购订单. 如果要将其改变为INNER JOIN,及那些不包含符合条件采购订单的客户将被排除,要做到这点我们可以在Purchase集合上增加一个过滤条件:

   1: from c in dataContext.Customers
   2:  
   3: where c.Purchases.Any (p => p.Price > 1000)
   4:  
   5: select new {
   6:  
   7:              c.Name,
   8:  
   9:              Purchases =
  10:  
  11:                from p in c.Purchases
  12:  
  13:                where p.Price > 1000
  14:  
  15:                select new { p.Description, p.Price }
  16:  
  17:              };

 

这个查询稍微有点混乱,因为我们编写了两次相同的判定(Price > 1000).通过let语句我们可以去掉这个重复:

   1: from c in dataContext.Customers
   2:  
   3: let highValueP = from p in c.Purchases
   4:  
   5:                  where p.Price > 1000
   6:  
   7:                  select new { p.Description, p.Price }
   8:  
   9: where highValueP.Any()
  10:  
  11:   select new { c.Name, Purchases = highValueP };

 

这种风格的查询的非常灵活的,例如通过将Any改为Count,我们可以改写此查询去选择那些包含至少两个采购订单的客户:

   1: from c in dataContext.Customers
   2:  
   3: let highValueP = from p in c.Purchases
   4:  
   5:                  where p.Price > 1000
   6:  
   7:                  select new { p.Description, p.Price }
   8:  
   9: where highValueP.Count() >= 2
  10:  
  11:   select new { c.Name, Purchases = highValueP };

 

填充到具体类型

如果你想要得到一个中间结果,将数据填充到匿名类型当中是非常有用,但是如果要将结果集发送给客户端,则会有一些问题,因为匿名类型只能在一个方法内作为本地变量存在.一个代替的方法就是使用具体类型作为数据载体,例如DataSet或者自定义的实体类.一个业务实体类就是一个包含某些自定义属性的类型,类似于那些标记了[Table]注解的LINQ to SQL类型,它们被设计用于隐藏数据库的细节.我们可能在实体类中排除外键字段,例如,假设我们编写了叫做CustomerEntity和PurcahseEntity的实体类,以下示例显示我们如何运用实体类来搭载数据:

   1: IQueryable query =
   2:  
   3:          from c in dataContext.Customers
   4:  
   5:          select new CustomerEntity
   6:  
   7:          {
   8:  
   9:            Name = c.Name,
  10:  
  11:            Purchases = (
  12:  
  13:              from p in c.Purchases
  14:  
  15:              where p.Price > 1000
  16:  
  17:              select new PurchaseEntity
  18:  
  19:              {
  20:  
  21:                Description = p.Description,
  22:  
  23:                Value = p.Price
  24:  
  25:              }
  26:  
  27:            ).ToList( )
  28:  
  29:          };
  30:  
  31:  
  32:  
  33:          List result = query.ToList();

 

到目前为止,我们并没有使用Join或者SelectMany,这是因为我们正在维护的是一个层级数据.使用LINQ,我们经常可以比避免使用传统的SQL途径来生成二维数据结果集.

(责任编辑:IT教学网)

更多

推荐ASP.NET教程文章