首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

NHibernate實戰(13):立即加載機制全解析

     編輯:關於.NET

前言

上一篇介紹了 NHibernate 默認的延遲加載機制(基於 Proxy 模式),本文將系統分析立即加載的三種實現方式:lazy="false" 屬性、NHibernateUtil 工具類、HQL 抓取策略。

立即加載機制示意

立即加載即在載入主對象時同步載入關聯集合,與延遲加載相反。通過一對多、多對多兩類關係實例深度解析。

一對多關係實例:Customer → Orders

方法一:映射文件設定 lazy="false"

修改 Customer.hbm.xml 中 <set> 元素:

<set name="Orders" ... lazy="false">

測試代碼:

[Test]
public void EagerLoadUsingLazyFalseTest()
{
    Customer customer = _relation.LazyLoadUsingSession(1);
    Assert.IsTrue(NHibernateUtil.IsInitialized(customer.Orders));
}

結果:生成兩條 SQL,分別查詢 Customer 與關聯 Orders。集合類型為 Iesi.Collections.Generic.HashedSet,但若在 using 區塊外訪問會拋出異常,驗證了立即加載在 Session 關閉前完成數據獲取。

方法二:NHibernateUtil.Initialize 強制初始化

修改 DAL 方法,在 Session 關閉前調用初始化:

public Customer EagerLoadUsingSessionAndNHibernateUtil(int customerId)
{
    using (ISession _session = new SessionManager().GetSession())
    {
        Customer customer = _session.Get<Customer>(customerId);
        NHibernateUtil.Initialize(customer.Orders);
        return customer;
    }
}

測試結果與方法一致,適用於映射文件不可修改或需動態控制的場景。

多對多關係實例:Order ↔ Products

方法一:lazy="false" 屬性

同理在多對多映射的 <bag> 設定 lazy="false"。注意:關閉延遲加載後,持久化類屬性可不再強制 virtual,但建議保持默認延遲加載以獲取性能優勢,僅在特殊場景啟用立即加載。

方法二:NHibernateUtil 初始化多重關聯

DAL 方法同時初始化 Customer(多對一)與 Products(多對多):

public Order EagerLoadOrderAggregateSessionAndNHibernateUtil(int orderId)
{
    using (ISession _session = new SessionManager().GetSession())
    {
        Order order = _session.Get<Order>(orderId);
        NHibernateUtil.Initialize(order.Customer);
        NHibernateUtil.Initialize(order.Products);
        return order;
    }
}

SQL 分析:一次立即加載生成四條 SQL,分別查詢 Order、Customer、OrderProduct 關聯表與 Product。雖獲取完整對象圖,但可能載入未使用數據,需權衡性能。

方法三:HQL 抓取策略——最高效方案

使用 fetch 關鍵字在單次查詢中完成多表連接:

public Order EagerLoadOrderAggregateWithHQL(int orderId)
{
    using (ISession _session = new SessionManager().GetSession())
    {
        return _session.CreateQuery("from Order o " +
            "left outer join fetch o.Products " +
            "inner join fetch o.Customer where o.OrderId=:orderId")
            .SetInt32("orderId", orderId)
            .UniqueResult<Order>();
    }
}

HQL Fetch 關鍵注意事項

  • 不可與 setMaxResults() 或 setFirstResult() 共用(結果集可能含重複行)
  • 不可與獨立 with 條件共用
  • 多集合 fetch 可能產生笛卡爾積
  • 多對多同時 join fetch 多角色可能結果非預期
  • full join fetch / right join fetch 無實際意義
  • 屬性級延遲加載可用 fetch all properties 強制立即獲取

生成 SQL 效果

單條 SQL 完成 Order、Customer、Products 三表連接查詢,極大減少資料庫往返:

SELECT ... FROM [Order] order0_
LEFT OUTER JOIN OrderProduct products1_ ON ...
LEFT OUTER JOIN Product product2_ ON ...
INNER JOIN Customer customer3_ ON ...
WHERE order0_.OrderId = @p0

結語

三種立即加載方案對比:

方案適用場景SQL 效率靈活性
lazy="false"全局固定策略多條 SQL低(靜態配置)
NHibernateUtil動態控制、映射不可改多條 SQL中(代碼控制)
HQL Fetch複雜關聯、追求極致性能單條 SQL(連接查詢)高(查詢級控制)

建議:默認使用延遲加載,按需採用 HQL Fetch 解決 N+1 問題,特殊場景輔以 NHibernateUtil。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved