Linq学习笔记(2.2)——深入DLinq查询

1:查询语句的执行
     Linq查询语句不向命令行语句一样会被立即执行,它仅仅是一个描述性的语句,例如在下面的语句:
var products = db.Products.Where(p => p.UnitPrice > 50);
foreach (var p in products)
     Response.Write(p.ProductName);
foreach (var p in products)
     Response.Write(p.UnitPrice);

   上面代码中products的实际类型是IQueryable<Product>,一个IQueryable对象就像一个ADO.NET command 对象,它本身并不会引发一次查询的执行,而仅仅保存了一个查询的描述,同样,一个IQueryable仅仅保存了一个可编译为数据库可理解的查询表达的描述,一个command对象的ExecuteReader()的方法会引发查询的真正执行,IQueryable对象有一个GetEnumerator()方法会引发Linq查询语句的执行返回一个IEnumerator<Product>对象。向上面代码中查询会因为两次foreach而被执行两次。这种行为我们称为延迟执行。
    但是通常情况下我们希望查询语句只执行一次,结果为后面的代码重复利用,一种通用的做法是用ToArray()或ToList()将结果结果转化为数组或集合,然后使用。

var products = db.Products.Where(p => p.UnitPrice > 50);
var productlist 
= products.ToList();
foreach (var p in productlist)
     Response.Write(p.ProductName);
foreach (var p in productlist)
     Response.Write(p.UnitPrice);

    延迟执行的优点是可以分段构造查询语句,比如你可以先构造查询语句的一部分,在根据条件构造另外一部分,在下面的例子中,我们先查处被订购次数大于30的产品,再根据条件判断是按价格还是按id排序!

var products = from p in db.Products
               where p.OrderDetails.Count 
> 30
               select p;
var orderbystring
=Request.QueryString["orderby"];
if (orderbystring == "UnitPrice")
{
      products 
= from p in products
                 orderby p.UnitPrice
                 select p;
}

else if (orderbystring == "id")
{
      products 
= from p in products
                 orderby p.ProductID
                 select p;
}

foreach (var p in products)
 Response.Write(p.ProductName
+"<br>");

2:关系查询
     在上次的练习中介绍了在实体类中通过关系特性来联系其他实体。如果实体定义了关系,则可以用以下语法来访问。
//查询产品ID为15的产品订单情况
var Orders = db.Products.Single(p => p.ProductID == 15).OrderDetails;
    当然如果没有在实体类定义属性也可以通过下面语法来查询:
var Orders = from p in db.Products
             from o 
in db.OrderDetails
             where p.ProductID 
== o.ProductID && p.ProductID == 15
             select p.OrderDetails;
或者
var Orders 
= from p in db.Products
             join o 
in db.OrderDetails on p.ProductID equals o.ProductID
             where p.ProductID 
== 15
             select p.OrderDetails;

      利用关系属性来定义实体,可以使我们方便的使用"."操作符,但这样定义实体对象最主要的原因是为了在使用一个类时不需要引入其他类,避免类与类之间的耦合性,

3:延迟加载与立即加载
    当你查询一个对象时,只想查询你想得到其中的一部分,比如你列举的所有的产品,而只有当某产品的价格大于50时才准备发货即只返回价格大于50的产品订单细节,而不是返回所有产品订单细节。这时候可以用Dlinq的延迟加载技术来实现。

var products = from p in db.Products
               select p;
foreach (var p in products)
{
       
if (p.UnitPrice > 50)
             SentProducts(p.OrderDetails);
}
    但有时你确实想同时得到相关的数据,比如上面的例子,在你得到产品的同时得到产品的订单情况,就只能使用下面的遍历的得出。
var products = from p in db.Products
           where p.UnitPrice
>50
               select p;
foreach (var p in products)
{
       
foreach (var o in p.OrderDetails)
       

             Response.Write(p.ProductID 
+ ":" + o.OrderID);
       }

}

    上面的例子的缺点时频繁的查询数据库,使数据库的负担过重,最好的做法是一次性返回产品及其订单情况,你可以用交叉或链接Dlinq查询代实现,但是这样返回的是大量数据,你可能需要定义新的匿名对象来转换这些数据,而不是原来的Product对象,而且这样可能会返回大量多余的数据,

DataShape ds = new DataShape();
ds.LoadWith
<Product>(p=>p.OrderDetails);
db.Shape 
= ds;        
var products 
= from p in db.Products
               where p.UnitPrice
>50
               select p;
foreach (var p in products){
      
foreach (var o in p.OrderDetails){
                Response.Write(p.ProductID 
+ ":" + o.OrderID);
      }

}
      DataShape的LoadWith方法就是通知FrameWork在返回Product时,同时返回它的订购情况。同时我们还可以用DataShape的AssociateWith方法来实现关系的子查询。
Northwind db = new Northwind("data source=.\\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=Northwind;");
        DataShape ds 
= new DataShape();
        ds.AssociateWith
<Product>(p => p.OrderDetails.Where(o => o.OrderID > 10500));
        db.Shape 
= ds;        
        var products 
= from p in db.Products
                       where p.UnitPrice
>50
                       select p;
        
foreach (var p in products){
            Response.Write(p.ProductID 
+ "——————<br>");
            
foreach (var o in p.OrderDetails){
                Response.Write(
" ProductID:" + p.ProductID + "-- OrderID:" + o.OrderID + "<br>");
            }

        }
posted @ 2007-06-10 18:35  Young.Jiang  阅读(3770)  评论(6编辑  收藏  举报