延迟加载与惰性加载
延迟加载与惰性加载(也叫贪婪加载)都是为了减少不必要的性能损耗。
1、延迟加载
延迟加载即返回实体时,其他关联实体并不返回,在使用其关联实体时,才重新打开数据库连接,查询后返回。
与 Entity Framework
不同的是,在使用延迟加载返回实体时,EntityContext
并不需要处于开启状态。
[TestMethod]
public void TestLazyLoad()
{
OrderDetails detail;
using (var db = new DbContext())
{
detail = db.OrderDetails.FirstOrDefault();
}
Assert.AreEqual("VINET", detail.Orders.CustomerID);
}
同样也实用于子实体集的加载。
[TestMethod]
public void TestLazyLoadDetails()
{
Orders order;
using (var db = new DbContext())
{
order = db.Orders.FirstOrDefault();
}
Assert.AreEqual(3, order.OrderDetailses.Count);
}
应注意延迟加载的性能影响,在处理集合的循环中,如果使用关联实体,将产生严重的性能影响,相当于循环里对每一个实体进行了一次查询。
[TestMethod]
public void TestLazyLoadLoop()
{
using (var db = new DbContext())
{
//将生产 1 + 5 次查询
foreach (var detail in db.OrderDetails.Take(5))
{
Assert.IsFalse(string.IsNullOrEmpty(detail.Orders.CustomerID));
}
}
}
为了避免这样的情况,我们建议你使用惰性加载。
2、惰性加载
正在上节所说一样,在循环处理集合时,如果使用了关联实体,那么将对性能产生严重影响。惰性加载是在查询时将关联实体一并返回,这样循环时不会产生延迟加载。 使用 Include 方法,指定需要加载的关联实体,你可以使用多次指定,最终结果都能够将关联实体一起返回。
[TestMethod]
public void TestInclude()
{
using (var db = new DbContext())
{
var details = db.OrderDetails
.Include(s => s.Products)
.Include(s => s.Orders);
foreach (var detail in details)
{
Console.WriteLine(detail.Products.ProductName);
Console.WriteLine(detail.Orders.OrderDate);
}
}
}
Include 还可以使用多层级联,跟踪 SQL
你会发现只产生了一次查询。
[TestMethod]
public void TestIncludeCascade()
{
using (var db = new DbContext())
{
var details = db.OrderDetails
.Include(s => s.Orders.Customers)
.Take(3);
foreach (var detail in details)
{
Console.WriteLine(detail.Orders.Customers.Address);
}
}
}
有时候在返回单个实体时,会使用到延迟加载技术返回关联实体,为了提高效率,也可以使用 Include 再使用 FirstOrDefault 返回实体。
[TestMethod]
public void TestIncludeGet()
{
using (var db = new DbContext())
{
var detail = db.OrderDetails
.Include(s => s.Products)
.Include(s => s.Orders)
.FirstOrDefault(s => s.OrderID == 1 && s.ProductID == 1);
Assert.AreEqual(detail.Orders.CustomerID, "VINET");
}
}
Include 也可以用于加载子实体集,以及子实体集中关联的其他实体属性,如下所示:
[TestMethod]
public void TestIncludeDetails()
{
using (var db = new DbContext())
{
var orders = db.Orders
.Include(s => s.OrderDetails)
.ThenInclude(s => s.Products)
.Include(s => s.Customers)
.ToList();
Console.WriteLine(orders[0].OrderDetails.Count);
}
}