[轉]NHibernate之旅(12):初探消極式載入機制

來源:互聯網
上載者:User

標籤:blog   http   io   os   使用   ar   strong   for   資料   

本節內容

  • 引入
  • 消極式載入
  • 執行個體分析
    • 1.一對多關聯性執行個體
    • 2.多對多關係執行個體
  • 結語
引入

通過前面文章的分析,我們知道了如何使用NHibernate,比如CRUD操作、事務、一對多、多對多映射等問題,這篇我們初步探索NHibernate中的載入機制。

在討論之前,我們看看我們使用的資料模型,回顧一下第二篇建立的資料模型。

Customer與Orders是一對多關聯性,Order與Product是多對多關係。這一篇還是使用這個模型,有關具體配置和映射參考本系列的文章。

消極式載入(Lazy Loading)

消極式載入按我現在的理解應該叫“視需要載入(load-on-demand)”,“(delayed loading)”,“剛好及時載入(just-in-time loading)”在合適不過了。這裡按字面理解延遲彷彿變成了“延遲,延長,拖延時間”的意思。

NHibernate從1.2版本就預設支援了消極式載入。其實消極式載入的執行方式是使用GoF23中的代理模式,我們用一張圖片來大致展示消極式載入機制。

執行個體分析1.一對多關聯性執行個體

在一對多關聯性執行個體中,我們使用Customer對象與Order對象為例,在資料訪問層中編寫兩個方法用於在測試時調用,分別是:

資料訪問層中方法一:載入Customer對象

public Customer LazyLoad(int customerId){    return _session.Get<Customer>(customerId);}

資料訪問層中方法二:載入Customer對象並使用Using強制清理關閉Session

public Customer LazyLoadUsingSession(int customerId){    using (ISession _session = new SessionManager().GetSession())    {        return _session.Get<Customer>(customerId);    }}
1.預設消極式載入

調用資料訪問層中的LazyLoad方法載入一個Customer對象,NHibernate的預設消極式載入Customer關聯的Order對象。利用NHibernate提供有用類(NHibernateUtil)測試被關聯的Customer對象集合是否已初始化(也就是已載入)。

[Test]public void LazyLoadTest(){    Customer customer = _relation.LazyLoad(1);    Assert.IsFalse(NHibernateUtil.IsInitialized(customer.Orders));}

測試成功,觀察NHibernate產生SQL語句為一條查詢Customer對象的語句。我們使用調試發現,Orders對象集合的屬性值為:{Iesi.Collections.Generic.HashedSet`1[DomainModel.Entities.Order]},並可以同時看到Order對象集合中的項。如下:

2.消極式載入並關閉Session

同第一個測試相同,這個測試調用使用Using強制資源清理Session載入Customer對象的方法。

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

測試成功,其產生SQL語句和上面測試產生SQL語句相同。但是使用調試發現,Orders對象集合的屬性值為:NHibernate.Collection.Generic.PersistentGenericSet<DomainModel.Entities.Order> ,如果你進一步想看看Order對象集合中的項,它拋出了HibernateException異常:failed to lazily initialize a collection, no session or session was closed。如下:

2.多對多關係執行個體

同理,在多對多關係執行個體中,我們以Order對象與Products對象為例,我們在資料訪問層中寫兩個方法用於測試:

方法1:載入Order對象

public DomainModel.Entities.Order LazyLoadOrderAggregate(int orderId){    return _session.Get<DomainModel.Entities.Order>(orderId);}

方法2:載入Customer對象並使用Using強制清理關閉Session

public DomainModel.Entities.Order LazyLoadOrderAggregateUsingSession(int orderId){    using (ISession _session = new SessionManager().GetSession())    {        return _session.Get<DomainModel.Entities.Order>(orderId);    }}
1.預設消極式載入

調用資料訪問層中的LazyLoadOrderAggregate方法載入一個Order對象,NHibernate的預設消極式載入Order關聯的Products對象集合(多對多關係),利用代理模式載入Customer對象集合(多對一關聯性)。利用NHibernate提供有用類(NHibernateUtil)測試被關聯的Products對象集合和Customer對象集合是否已初始化。

[Test]public void LazyLoadOrderAggregateTest(){    Order order = _relation.LazyLoadOrderAggregate(2);    Assert.IsFalse(NHibernateUtil.IsInitialized(order.Customer));    Assert.IsFalse(NHibernateUtil.IsInitialized(order.Products));}

測試成功,NHibernate產生SQL語句如下:

SELECT order0_.OrderId as OrderId1_0_,       order0_.Version as Version1_0_,       order0_.OrderDate as OrderDate1_0_,       order0_.Customer as Customer1_0_FROM [Order] order0_ WHERE [email protected]; @p0 = ‘2‘

調試看看效果,可以清楚的觀察到Customer對象和Products對象集合的類型。

2.消極式載入並關閉Session

同第一個測試相同,這個測試調用使用Using強制資源清理Session載入Order對象的方法。

[Test]public void LazyLoadOrderAggregateUsingSessionTest(){    Order order = _relation.LazyLoadOrderAggregateUsingSession(2);    Assert.IsFalse(NHibernateUtil.IsInitialized(order.Customer));    Assert.IsFalse(NHibernateUtil.IsInitialized(order.Products));}

測試成功,其產生SQL語句和上面測試產生SQL語句相同。但是使用調試發現,Customer物件類型為:{CustomerProxy9dfb54eca50247f69bfedd92e1638ba5},進一步觀察Customer對象Firstname、Lastname等項引發了“NHibernate.LazyInitializationException”類型的異常。Products對象集合的屬性值為:{NHibernate.Collection.Generic.PersistentGenericBag<DomainModel.Entities.Product>},如果你進一步想看看Products對象集合中的項它同樣拋出HibernateException異常:failed to lazily initialize a collection, no session or session was closed。下面截取擷取Customer對象一部分圖,你想知道全部自己親自調試一把:

3.消極式載入中LazyInitializationException異常

上面測試已經說明了這個問題:如果我想在Session清理關閉之後訪問Order對象中的某些項會得到一個異常,由於session關閉,NHibernate不能為我們消極式載入Order項,我們編寫一個測試方法驗證一下:

[Test][ExpectedException(typeof(LazyInitializationException))]public void LazyLoadOrderAggregateUsingSessionOnFailTest(){    Order order = _relation.LazyLoadOrderAggregateUsingSession(2);    string name = order.Customer.Name.Fullname;}

上面的測試拋出“Could not initialize proxy - no Session”預計的LazyInitializationException異常,表明測試成功,證明不能載入Order對象的Customer對象。

4.N+1選擇問題

我們在載入Order後訪問Product項,導致訪問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);}

NHibernate產生SQL語句如下:

SELECT order0_.OrderId as OrderId1_0_,       order0_.Version as Version1_0_,       order0_.OrderDate as OrderDate1_0_,       order0_.Customer as Customer1_0_ FROM [Order] order0_ WHERE [email protected]; @p0 = ‘2‘SELECT products0_.[Order] as Order1_1_,        products0_.Product as Product1_,       product1_.ProductId as ProductId3_0_,       product1_.Version as Version3_0_,       product1_.Name as Name3_0_,       product1_.Cost as Cost3_0_ FROM OrderProduct products0_ left outer join Product product1_ on products0_.Product=product1_.ProductId WHERE products0_.[Order][email protected]; @p0 = ‘2‘

這次我走運了,NHibernate自動產生最佳化的查詢語句,一口氣載入了兩個Product對象。但是試想一下有一個集合對象有100項,而你僅僅需要訪問其中的一兩項。這樣載入所有項顯然是資源的浪費。

幸好,NHibernate為這些問題有一個方案,它就是立即載入。欲知事後如何,請聽下回分解!

[轉]NHibernate之旅(12):初探消極式載入機制

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.