01-05-01-1【Nhibernate (版本3.3.1.4000) 出入江湖】消極式載入及其class和集合(set、bag等)的Lazy屬性配置組合對Get和Load方法的影響

來源:互聯網
上載者:User

標籤:style   c   class   blog   code   java   

這篇文章

http://ayende.com/blog/3988/nhibernate-the-difference-between-get-load-and-querying-by-id

One of the more common mistakes that I see people doing with NHibernate is related to how they are loading entities by the primary key. This is because there are important differences between the three options.The most common mistake that I see is using a query to load by id. in particular when using Linq for NHibernate.var customer = (    select customer from s.Linq<Customer>()    where customer.Id = customerId    select customer    ).FirstOrDefault();Every time that I see something like that, I wince a little inside. The reason for that is quite simple. This is doing a query by primary key. The key word here is a query.This means that we have to hit the database in order to get a result for this query. Unless you are using the query cache (which by default you won’t), this force a query on the database, bypassing both the first level identity map and the second level cache.Get  and Load are here for a reason, they provide a way to get an entity by primary key. That is important for several aspects, most importantly, it means that NHibernate can apply quite a few optimizations for this process.

 

 

好像在說,不要用主鍵(by primary key)去查詢,因為用主鍵區查詢會繞開一級和二級緩衝。

所以建議用Get和Load去查詢

 

下面的測試是錯誤的,要看正確的蓋棺定論,請跳轉至:
終極測試:

--------------------------------------------

 

實現消極式載入:

 如何?消極式載入:

       要在實現消極式載入的類的對應檔xxx.hbm.xml中添加  lazy="true",根據加的位置,有兩種:

一是類層級的:

  <class name="Model.Customer, Model"         table="Customer"         discriminator-value="0" lazy="true">    <!--unsaved-value="0" 主鍵表中不需要定義,而是需要在子表中定義-->    <id name="CustomerId"        column="CustomerId"        type="int"         unsaved-value="0">      <generator class="native" />
。。。。

 

二是集合層級的

 

  <class name="Model.Customer, Model"         table="Customer"         discriminator-value="0">。。。。。    <set name="Orders" table="Order"  lazy="true"         generic="true"          inverse="true" cascade="all">      <key column="CustomerId" foreign-key="FK_CustomerOrders"/>       <one-to-many class="Model.Order,Model"/>    </set>。。。

 

根據目前的測試,集合位置的消極式載入配置會覆蓋類層級的消極式載入配置。

 

有兩種擷取實體的方法:Get和Load方法。測試了如下組合:

 

                   類層級的lazy="true"  且                 類層級的lazy="true"且

                   集合層級的lazy="true"                  集合層級的lazy="false"

--------------------------------------------------------------------------

Get方法     |        載入父,消極式載入子                     父子都非消極式載入

Load方法   |        父子都非消極式載入                        父子都非消極式載入

 

從上面可以看到:

         Load方法是不理會lazy="true" 配置的,永遠的是非消極式載入。用Lode方法擷取Customer時,Customer和子集合Order永遠都是立即載入(不管哪裡配置了lazy =“true”)。

剛好和:

http://blog.knowsky.com/192505.htm

描述的完全相反。到底誰對誰錯,糾結啊

 

通過一夜的調試:

發現,如果是設斷點去調試,那麼Load表現為非消極式載入,發送了SQL語句,

這可能是編譯器的問題。上面說的

剛好和:

http://blog.knowsky.com/192505.htm

描述的完全相反。到底誰對誰錯,糾結啊


應該可以更正回來了,

                   類層級的lazy="true"  且                 類層級的lazy="true"且

                   集合層級的lazy="true"                  集合層級的lazy="false"

--------------------------------------------------------------------------

Get方法     |        載入父,消極式載入子                     父子都非消極式載入

Load方法   |        父子都消極式載入                          父子都非消極式載入

 

最終的結論是:

在配置lazy = “true”的情況下,

Get方法僅消極式載入子集合Orders,

Load方法比Get更牛逼,不僅消極式載入子集合Orders,把父Customer也消極式載入了。

  Load方法是假設父Customer是存在,若不存在,會引發異常“NHibernate.ObjectNotFoundException”類型的異常,

但是這種異常,Nhibernate自己內部處理了,並返回一個實體類的代理(CustmoeProxy),保證不返回一個null

如所示:

 

 

 

 

 

------------------------------------------

非消極式載入圖解:

 

 

消極式載入圖解:

 

 

看到,當實現消極式載入,當需要Orders時,會通過session去查詢,session。但此時,由於session已經關閉,

所以會拋出異常:

{"Initializing[Model.Customer#336]-failed to lazily initialize a collection of role: Model.Customer.Orders, no session or session was closed"}

為了避免session被關閉,消極式載入失敗。有如下解決方案:

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

以後就調用這個方法來擷取Orders

 

--------------------------------------------------------------------------------------------------------------
終極測試:


注意:測試時不要打斷點,否則會影響測試結果(如果打了斷點調試,會有多餘的SQl請求產生),上面的測試就是因為打了斷點去測試,結果
影響了測試結論。

測試的最終結論,上面所以的測試結論以下面的測試結果為蓋棺定論。

下面的<class>和<Set>都是屬於Customer.hbm.xml中的設定。

【1】Get方法:

                                                     <class  name ="Customer" lazy="true" >     <class  name ="Customer" lazy="false" >  

<set name="Orders" lazy="true">        載入Customer,不載入Orders                         載入Customer,不載入Orders 

<set name="Orders" lazy="false">       載入Customer,   載入Orders                         載入Customer,    載入Orders 

 
結論:1.Get方法永遠載入Customer;
2.Get方法是否載入Orders,由<set name="Orders" lazy="">決定。 



【2】Load方法:

                                                      <class  name ="Customer" lazy="true" >     <class  name ="Customer" lazy="false" >  

<set name="Orders" lazy="true">        Customer和Orders都不載入                          載入Customer,不載入Orders 

<set name="Orders" lazy="false">       Customer和Orders都不載入                          載入Customer,載入Orders 

 

 

 

    結論:1.Load方法只要Class的Lazy為false,永遠都不載入Customer和Orders;
2.Load方法只要Class的Lazy為ture,永遠載入Customer,是否載入Oders由<set name="Orders" lazy="">決定。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.