程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> NHibernate延遲加載機制 - NHibernate 2.1.2

NHibernate延遲加載機制 - NHibernate 2.1.2

編輯:關於.NET

NHibernate實現延遲加載的主要結構:

BuildSessionFactory的時候:

1. 根據proxyfactory.factory_class的配置創建IProxyFactoryFactory對象

2. 如果use_proxy_validator配置為true(默認為true),加載實體映射元數據之後,對需要代理的 實體使用 IProxyFactoryFactory的ProxyValidator進行驗證(例如要求實體有默認構造器、方法屬性必 須為virtual類型等)

3. 為需要代理的實體類型創建IProxyFactory,並調用IProxyFactory對象的PostInstantiate方法

對每一個需要代理的實體類型都會創建一個IProxyFactory對象並緩存,創建代理對象則通過 IProxyFactory的GetProxy方法完成

AbstractProxyFactory主要是實現PostInstantiate方法,這個方法主要是將創建代理對象所需的信息 記錄下來,例如 EntityName(字符串的實體類名)、PersistentClass(代理對象的System.Type)、 Interfaces(代理對象需要額外實現的接口,例如INHibernateProxy),其他幾個記錄的屬性則為單主鍵 和組合主鍵id的get、set方法

ProxyFactory則主要實現GetProxy方法,使用Castle或者LinFu等動態代理庫以及上述信息創建代理對 象

創建代理對象:

IProxyFactory.GetProxy方法完成

1. 創建一個LazyInitializer對象。LazyInitializer實現了各個動態代理類庫的攔截器接口

2. 通過Castle、LinFu、Spring等動態代理庫創建class proxy或者interface proxy的代理對象

創建代理對象時INHibernateProxy作為一個mixin的接口,NHibernate內部用這個接口來區分代理對象 和真實對象。對這個接口的方法調用則在攔截器中處理

延遲加載:

創建代理對象時,均使用NHibernate.ByteCode.LinFu或者NHibernate.ByteCode.Castle中的 LazyInitializer類作為攔截器,因此對代理對象的方法調用都在LazyInitializer中攔截處理

ILazyInitializer接口主要用於延遲加載的相關處理

首先,對代理對象某些方法的調用不會觸發延遲加載行為,比如讀取主鍵的值、組合類型屬性的主鍵 值、沒有override的情況下調用Object基類的一些方法以及Dispose方法等,這些邏輯在 BasicLazyInitializer的Invoke方法中處理

當調用代理對象的其他方法時,觸發延遲加載行為。加載處理在AbstractLazyInitializer的 Initialize方法中完成,加載實體所需要的信息(主要有session、id、實體的類型)在創建 LazyInitializer對象時均已經提供,加載過程仍然使用一級緩存、二級緩存、數據庫這樣一個加載順序

加載的實體對象與代理對象是兩個獨立的對象,NHibernate並沒有將加載後的實體屬性值設置到代理 對象上,估計一是考慮到有interface proxy存在的情況,另外實際加載過程是比較獨立的,他會重新創 建一個真實的實體對象,會放入一級、二級緩存中,還有一點,這種處理方式 NHibernate以及client都 可以通過代理對象來得到加載後的真實對象。真實的實體對象保存在AbstractLazyInitializer 的Target 屬性中,完成加載以後,攔截器中通過反射來調用target對象的方法

下面代碼示例怎麼由代理對象得到真實對象(非NHibernate官方公布的方法,慎用):

01 ISessionFactory sf = new Configuration().Configure().BuildSessionFactory ();
02 using (ISession session = sf.OpenSession())
03 {
04     //僅創建 代理對象,沒有實際加載 
05     MyUser proxy = session.Load<MyUser> (11);
06     Console.WriteLine(proxy.GetType().FullName);
07     //因為 override了ToString方法,因此下面這個調用將觸發加載行為
08     Console.WriteLine (proxy.ToString());
09     //獲取真實對象
10      NHibernate.Proxy.INHibernateProxy nhProxy = proxy as INHibernateProxy;
11      MyUser real = nhProxy.HibernateLazyInitializer.GetImplementation() as MyUser;
12      Console.WriteLine(real.GetType().FullName);
13     Console.WriteLine (real.ToString());
14 }
15 sf.Close();
16 Console.ReadKey();

下面是運行結果:

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved