標籤: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="">決定。