Linq学习笔记(2.2)——深入DLinq查询
Linq查询语句不向命令行语句一样会被立即执行,它仅仅是一个描述性的语句,例如在下面的语句:
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 productlist = products.ToList();
foreach (var p in productlist)
Response.Write(p.ProductName);
foreach (var p in productlist)
Response.Write(p.UnitPrice);
延迟执行的优点是可以分段构造查询语句,比如你可以先构造查询语句的一部分,在根据条件构造另外一部分,在下面的例子中,我们先查处被订购次数大于30的产品,再根据条件判断是按价格还是按id排序!
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:关系查询
在上次的练习中介绍了在实体类中通过关系特性来联系其他实体。如果实体定义了关系,则可以用以下语法来访问。
var Orders = db.Products.Single(p => p.ProductID == 15).OrderDetails;
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的延迟加载技术来实现。
select p;
foreach (var p in products)
{
if (p.UnitPrice > 50)
SentProducts(p.OrderDetails);
}
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对象,而且这样可能会返回大量多余的数据,
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 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>");
}
}