基於經典 Customer-Order-Product 數據模型,本文從一對多、多對多兩個維度深度剖析 NHibernate 默認的延遲加載機制,揭示 Proxy 代理模式實現原理與常見陷阱。
NHibernate 1.2+ 默認啟用延遲加載,本質採用 GoF 23 種設計模式中的代理模式。當訪問關聯屬性時,動態生成代理對象,僅在真正需要時發送 SQL 查詢。
// 正常 Session 生命週期
public Customer LazyLoad(int customerId)
=> _session.Get<Customer>(customerId);
// 強制關閉 Session 模擬 Web 請求結束
public Customer LazyLoadUsingSession(int customerId)
{
using (ISession session = new SessionManager().GetSession())
return session.Get<Customer>(customerId);
}
[Test]
public void LazyLoadTest()
{
Customer customer = _relation.LazyLoad(1);
Assert.IsFalse(NHibernateUtil.IsInitialized(customer.Orders));
}
Iesi.Collections.Generic.HashedSet<Order>[Test]
public void LazyLoadUsingSessionTest()
{
Customer customer = _relation.LazyLoadUsingSession(1);
Assert.IsFalse(NHibernateUtil.IsInitialized(customer.Orders));
}
NHibernate.Collection.Generic.PersistentGenericSet<Order>HibernateException: failed to lazily initialize a collection, no session or session was closedpublic Order LazyLoadOrderAggregate(int orderId)
=> _session.Get<Order>(orderId);
public Order LazyLoadOrderAggregateUsingSession(int orderId)
{
using (ISession session = new SessionManager().GetSession())
return session.Get<Order>(orderId);
}
CustomerProxy...(多對一延遲)Iesi.Collections.Generic.HashedSet<Product>NHibernateUtil.IsInitialized 均返回 falseLazyInitializationException: Could not initialize proxy - no SessionHibernateException: failed to lazily initialize a collectionPersistentGenericBag<Product>[Test]
public void LazyLoadOrderAggregateSelectBehaviorTest()
{
Order order = _relation.LazyLoadOrderAggregate(2);
float sum = 0.0F;
foreach (var item in order.Products)
sum += item.Cost;
Assert.AreEqual(21.0F, sum);
}
SQL 結果:NHibernate 智能優化,單條左連接查詢加載所有 Product,避免 N+1。但大集合場景下仍存在效能隱患。
| 場景 | 關聯類型 | 集合/代理類型 | Session 關閉後訪問 |
|---|---|---|---|
| 一對多 | Set | PersistentGenericSet | HibernateException |
| 多對一 | Proxy | CustomerProxy... | LazyInitializationException |
| 多對多 | Bag | PersistentGenericBag | HibernateException |
延遲加載雖節省初始查詢資源,但帶來 Session 管理複雜度與 N+1 風險。下篇將介紹立即加載機制,提供解決方案。關鍵實踐建議: