前言:
本篇涉及的代碼由C#語言描述,但並不妨礙其他語言的面向對象設計師閱讀,旨在理解O/RM延遲加載的原理,減少開發者出現由O/RM引起的性能問題時大叫“怎么會這樣?”的幾率。
本篇並不會詳細介紹代理模式,也不詳細介紹延遲加載,因為這並不是本篇的重點。
本篇隨筆的重點是幫助理解延遲加載的原理,透過這個原理,我們將會知道為什么Nhibernate(O/RM)的領域模型的成員都需要加上virtual關鍵字,也能更好地理解Nhibernate的延遲加載(當然我相信很少會不借助框架而純手工去實現延遲加載)。
我們先來看一個非常簡單的例子:
這個Class1我就暫且當它是一個領域模型,屬性Name是我們需要觀察的延遲加載成員,而ShowStatus是幫助我們觀察延遲加載的狀態。

public class Class1 { public virtual string Name { get; set; } public virtual bool ShowStatus { get; set; } }
這個Class1Proxy是代理類,我們重寫而來ShowStatus是為了輸出狀態,可以看到我們用override重寫了Name的Get訪問器。

internal class Class1Proxy:Class1 { private bool _nameLoaded = false; public override bool ShowStatus { get { return _nameLoaded; } } public override string Name { get { string name; if (!_nameLoaded) { name = "name was loaded"; //模擬從數據庫加載數據 _nameLoaded = true; base.Name = name; //當做緩存 } else { name = base.Name; //已經加載的情況加使用緩存 } return name; } set { base.Name = value; _nameLoaded = true; } } }
暫時用Mapping類來充當持久化的過程,注意實例化的時候其實是持久化了Proxy,而實際使用當中你不會察覺到你用的是Class1Proxy而不是Class1。

public class Mapping { public Class1 Build() { Class1 c1 = new Class1Proxy(); return c1; } }
測試代碼如下,由於我台式機的IDE正好發生了問題,所以就沒有使用測試框架,直接輸出吧。

Class1 c1 = new Class1(); Mapping mapping = new Mapping(); c1=mapping.Build(); Response.Write(c1.ShowStatus+"<br/>"); Response.Write(c1.Name + "<br/>"); Response.Write(c1.ShowStatus + "<br/>");
輸出結果:
False
name was loaded
True
結果可以看到,剛持久化以后Name並沒有被加載(可以看到Mapping.Build方法中並沒有持久化Name),所以輸出了False,然后客戶端試着輸出c1.Name,也就在這時才開始加載Name,然后我們發現輸出時Name已經有數據了。
討論:
在這個例子當中使用了一個簡單的代理,正是因為virtual關鍵字,使得延遲加載得以實現,而實際上在java中所有成員默認就是virtual的,所以在Hibernate中並不需要加這個關鍵字,並不是因為Nhibernate在移植過程中殘疾了,而是本該如此。
如果使用Nhibernate時放棄延遲加載的功能擇可以不必設置動態代理,也就可以不必處處加上virtual關鍵字,但在領域驅動設計中這並不是個好主意。
最后感謝你可以看到這里,希望本篇的介紹會對你有所幫助。