LINQ to SQL语句(17)之对象加载

对象加载

延迟加载

在查询某对象时,实际上你只查询该对象。不会同时自动获取这个对象。这就是延迟加载。

例如,您可能需要查看客户数据和订单数据。你最初不一定需要检索与每个客户有关的所有订单数据。其优点是你可以使用延迟加载将额外信息的检索操作延迟到你确实需要检索它们时再进行。请看下面的示例:检索出来CustomerID,就根据这个ID查询出OrderID。

var custs =
from c in db.Customers
where c.City == "Sao Paulo"
select c;
//上面的查询句法不会导致语句立即执行,仅仅是一个描述性的语句,只有需要的时候才会执行它
foreach (var cust in custs)
{
foreach (var ord in cust.Orders)
{
//同时查看客户数据和订单数据
}
}

语句描述:原始查询未请求数据,在所检索到各个对象的链接中导航如何能导致触发对数据库的新查询。

预先加载:LoadWith 方法

你如果想要同时查询出一些对象的集合的方法。LINQ to SQL 提供了 DataLoadOptions用于立即加载对象。方法包括: LoadWith 方法,用于立即加载与主目标相关的数据。 AssociateWith 方法,用于筛选为特定关系检索到的对象。

使用 LoadWith方法指定应同时检索与主目标相关的哪些数据。例如,如果你知道你需要有关客户的订单的信息,则可以使用 LoadWith 来确保在检索客户信息的同时检索订单信息。使用此方法可仅访问一次数据库,但同时获取两组信息。 在下面的示例中,我们通过设置DataLoadOptions,来指示DataContext在加载Customers的同时把对应的Orders一起加载,在执行查询时会检索位于Sao Paulo的所有 Customers 的所有 Orders。这样一来,连续访问 Customer 对象的 Orders 属性不会触发新的数据库查询。在执行时生成的SQL语句使用了左连接。

NorthwindDataContext db = new NorthwindDataContext();
DataLoadOptions ds = new DataLoadOptions();
ds.LoadWith<Customer>(p => p.Orders);
db.LoadOptions = ds;
var custs = (
from c in db2.Customers
where c.City == "Sao Paulo"
select c);
foreach (var cust in custs)
{
foreach (var ord in cust.Orders)
{
Console.WriteLine("CustomerID {0} has an OrderID {1}.",
cust.CustomerID,
ord.OrderID);
}
}

语句描述:在原始查询过程中使用 LoadWith 请求相关数据,以便稍后在检索到的各个对象中导航时不需要对数据库进行额外的往返。

延迟加载:AssociateWith方法

使用 AssociateWith 方法指定子查询以限制检索的数据量。 在下面的示例中,AssociateWith 方法将检索的 Orders 限制为当天尚未装运的那些 Orders。如果没有此方法,则会检索所有 Orders,即使只需要一个子集。但是生成SQL语句会发现生成了很多SQL语句。

NorthwindDataContext db2 = new NorthwindDataContext();
DataLoadOptions ds = new DataLoadOptions();
ds.AssociateWith<Customer>(
p => p.Orders.Where(o => o.ShipVia > ));
db2.LoadOptions = ds;
var custs =
from c in db2.Customers
where c.City == "London"
select c;
foreach (var cust in custs)
{
foreach (var ord in cust.Orders)
{
foreach (var orderDetail in ord.OrderDetails)
{
//可以查询出cust.CustomerID, ord.OrderID, ord.ShipVia,
//orderDetail.ProductID, orderDetail.Product.ProductName
}
}
}

语句描述:原始查询未请求数据,在所检索到各个对象的链接中导航如何以触发对数据库的新查询而告终。此示例还说明在延迟加载关系对象时可以使用 Assoicate With 筛选它们。

预先加载:LoadWith方法和Associate With方法

这个例子说明:使用LoadWith方法来确保在检索客户信息的同时检索订单信息,在检索订单信息的同时检索订单详细信息, 仅仅访问一次数据库。即可以在一个查询中检索许多对象。使用Associate With方法来限制订单详细信息的排序规则。

NorthwindDataContext db2 = new NorthwindDataContext();
DataLoadOptions ds = new DataLoadOptions();
ds.LoadWith<Customer>(p => p.Orders);
ds.LoadWith<Order>(p => p.OrderDetails);
ds.AssociateWith<Order>(
p => p.OrderDetails.OrderBy(o => o.Quantity));
db2.LoadOptions = ds;
var custs = (
from c in db2.Customers
where c.City == "London"
select c);
foreach (var cust in custs)
{
foreach (var ord in cust.Orders)
{
foreach (var orderDetail in ord.OrderDetails)
{
//查询cust.CustomerID, ord.OrderID
//orderDetail.ProductID, orderDetail.Quantity
}
}
}

语句描述:在原始查询过程中使用 LoadWith 请求相关数据,以便稍后在检索到的各个对象中导航时此示例还说明在急切加载关系对象时可以使用 Assoicate With 对它们进行排序。

加载重写

这个例子在Category类里提供了一个LoadProducts分部方法。当产品的类别被加载的时候,就直接优先调用了LoadProducts方法来查询没有货源的产品。

private IEnumerable<Product> LoadProducts(Category category)
{
//在执行LINQ to SQL的时候,这个LoadProducts分部方法
//优先加载执行,这里用存储过程也可以.
return this.Products
.Where(p => p.CategoryID == category.CategoryID)
.Where(p => !p.Discontinued);
}

执行下面的查询时,利用上面方法返回的数据进行下面的操作:

NorthwindDataContext db2 = new NorthwindDataContext();
DataLoadOptions ds = new DataLoadOptions();
ds.LoadWith<Category>(p => p.Products);
db2.LoadOptions = ds;
var q = (
from c in db2.Categories
where c.CategoryID <
select c);
foreach (var cat in q)
{
foreach (var prod in cat.Products)
{
//查询cat.CategoryID, prod.ProductID
}
}

语句描述:重写 Category 类中的分部方法 LoadProducts。加载某种类别的产品时,调用 LoadProducts 以加载此类别中未停产的产品。

上一篇:QT中的sender()函数


下一篇:LinqToDB 源码分析——生成与执行SQL语句