為什麼Nhibernate中屬性和方法必須Virtual的

來源:互聯網
上載者:User

標籤:style   class   blog   http   color   com   

如果你曾經用過NHibernate 2.0或者更高的版本,那您一定碰到過下面的錯誤:NHibernate.InvalidProxyTypeException: The following types may not be used as proxies:
NHibernateExamples.Entities.OrderLine: method get_UnitPrice should be ‘public/protected virtual‘ or ‘protected internal virtual‘
NHibernateExamples.Entities.OrderLine: method set_UnitPrice should be ‘public/protected virtual‘ or ‘protected internal virtual‘

哎呀,我們忘記把OrderLine實體中的UnitPrice屬性標誌成virtual的了,奇怪的是,為什麼它一開始的時候必須要設定成virtual的,這是一個對於初次接觸NHibernate的人經常有的疑惑。

針對這個問題,最簡潔的答案就是:因為我們需要把成員設定成virtual的,是為了實現我們的消極式載入的魔幻功能。

但是更詳細點的答案反而更有趣,我們知道任何真正的ORM必須要有的一個重要功能就是消極式載入,如果你通過ORM擷取一個對象,你不會希望它去自動的擷取整個對象圖中所有資料(預設情況下應當不是), 還有你也不希望添加一些淩亂的代碼去檢查特定的關聯關係是否已經被載入了,我們需要的是只有我們的需要的時候才去載入它們。這應該是ORM的職責。理想情況下應該是,你能訪問這些屬性,而且如果這時資料還沒有載入,當你第一次訪問的時候,ORM會負責載入當前需要的資料。

NHiernate 擁有這項能力,但是它卻不要求你繼承NHibernate中的某項基類或者實現一些介面。那奇怪了? Nhibernate是怎麼做到的呢?其實,當需要消極式載入時,在運行期,Nhibernate用的是你的類的代理(proxy)。 那代理又是什麼呢? 一個Nhibernate代理指的是當你的程式初始化Nhibernate的時候(發生在應用程式第一次啟動的時候,並且只發生一次),Nhibernate動態產生的一個類型。如果你沒有顯示的給你的Entity指定不需要消極式載入,那Nhibernate會為你的每一個Entity產生一個代理,每一個Entity代理的類型其實是繼承與這個Entity的。這樣你在操作這個類型的時候,你就可以做一些攔截操作。

為了使這個過程變得更清晰,我們舉個小例子。假設你有一個Order類,這個Order類有一些屬性如Employee,Customer和其它。 但是當你載入Order實體的時候,你也許不想讓Employee屬性已經包含了真正的Employee執行個體。對於Cutomer屬性也是同樣的。預設情況下,Nhibernate認為每個實體類型都是要消極式載入的,除非你顯示的告訴它不用消極式載入。所以,當Nhibernate一開始初始化的時候,它會知道它需要動態為Customer和Employee組建代理程式(proxy)類型。在這我們假設兩個類型的名字為CustomerProxyType和EmployeeProxyType (在現實中它們不會叫這個名字,但是這個不重要). 現在假設你去擷取Order執行個體,這時你還沒有去請求Customer或者Employee的資料,所以它們應當是不存在的,對吧? 但是它們也不為Null, 因為Nhibernate 為Customer屬性分配了CustomerProxyType的執行個體,為Employee屬性分配了EmployeeProxyType執行個體。並且還為每一個執行個體初始化了它們的標識符的值,一般是ID的值。這個標識符的值是在查詢order記錄的時候擷取到的。

你現在可以放心的使用Order執行個體,你甚至可以訪問Employee和Customer的執行個體,這時什麼也不會發生,不會有查詢操作。但是,注意,當你去訪問代理執行個體的非標識符成員(也就是屬性和方法)的時候,Nhibernate為了確保你請求的非標識符成員有資料,它會去資料庫請求資料。在這裡就是當你去訪問Employee和Customer的屬性和方法的時候,Nhibernate會去資料庫請求你想要的資料。那Nhibernate是怎麼實現的這種機制呢? 因為代理會重寫你的實體類(Entity)的屬性和方法,當屬性和方法被調到的時候,Nhibernate會檢查,如果當前執行個體的資料已經存在了,它就只會調用實體類(Entity)中屬性和方法的實現,如果沒有資料,它會先去擷取資料,然後再調用實體類(Entity)中屬性和方法的實現。

這是基本的面相對象思想,你的實體類(Entity)是Nhibernate 代理的基類。 這些代理(proxy)會為你的實體類(Entity)的行為上添加一些額外的行為。 Nhibernate需要重寫所有的公用成員(public)來確保在合適的時間這些額外的行為能被觸發。

聯繫我們

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