国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

淺析NHibernate一對一映射的延遲加載

開發(fā) 后端
筆者由于項目需要,最近對.NET平臺下各ORM框架(LINQ to SQL、Entity Framework V2 & V4、以及NHibernate)進行了功能對比,NHiberante可以說是各框架之中歷史最為悠久,功能最強,也是使用最為復雜的一個。本文將介紹NHibernate一對一映射的延遲加載。

在使用NHibernate的過程中也遇到了許多麻煩,不過也得到了不少體會。例如NH的不足之處,我理想中的ORM框架是怎么樣的,等等這些,以后有機會也可以慢慢和各位進行討論。

不過這篇文章談論的其實只是一個小技巧,一個workaround,而且甚至于這個是由于我對NHibernate不夠了解而造成的。因此,如果您有更好的做法也請不吝指出。這個問題也就是“如何實現(xiàn)NHibernate一對一映射的延遲加載”。

NHibernate一對一映射問題描述

之前對于問題的描述,其實還有很多額外的要求沒有講清楚,而需要“workaround”的現(xiàn)狀,也是這些要求共同形成的。經(jīng)過嘗試,如果放棄其中任何一個(如把主表ID的生成策略從identity改為native),則可能就會有更直接的做法了。這些條件是:

NHibernate一對一映射

主鍵關聯(lián)

主表的ID為自增字段

所有字段NOT NULL。

主表和子表設置級聯(lián)刪除

現(xiàn)在的問題,就是在這些條件下,如何實現(xiàn)“獲取主表對象時,并不加載其對應的子表數(shù)據(jù)”,也就是所謂的“延遲加載”。當然,除了能夠“延遲加載”以外,還必須可以插入,更新和刪除——我也嘗試過使用某些特殊的映射方式,可以實現(xiàn)延遲加載,但是卻無法插入,這自然也無法滿足要求。

為了便于理解和實驗,我在這里也將其“具體化”。首先是Model,User和UserDetail,它們是典型的一對一關系:

  1. public class User  
  2. {  
  3.     public virtual int UserID { get; set; }  
  4.     public virtual string Name { get; set; }  
  5.     public virtual UserDetail Detail { get; set; }  
  6. }  
  7.  
  8. public class UserDetail  
  9. {  
  10.     public virtual int UserID { get; set; }  
  11.     public virtual int Age { get; set; }  
  12.     public virtual User User { get; set; }  

而數(shù)據(jù)庫方面則是一個User表和一個UserDetail表:

  1. CREATE TABLE [dbo].[User](  
  2.     [UserID] [int] IDENTITY(1,1) NOT NULL,  
  3.     [Name] [nvarchar](50) NOT NULL,  
  4.  CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED   
  5. (  
  6.     [UserID] ASC  
  7. ))  
  8. GO  
  9.  
  10. CREATE TABLE [dbo].[UserDetail](  
  11.     [UserID] [int] NOT NULL,  
  12.     [Age] [int] NOT NULL,  
  13.  CONSTRAINT [PK_UserDetail] PRIMARY KEY CLUSTERED   
  14. (  
  15.     [UserID] ASC  
  16. ))  
  17. GO  
  18.  
  19. ALTER TABLE [dbo].[UserDetail]  WITH CHECK ADD  
  20. CONSTRAINT [FK_UserDetail_User] FOREIGN KEY([UserID])  
  21. REFERENCES [dbo].[User] ([UserID])  
  22. ON DELETE CASCADE  
  23. GO  
  24. ALTER TABLE [dbo].[UserDetail] CHECK CONSTRAINT [FK_UserDetail_User]  
  25. GO 

User表為主表,主鍵為UserID,自增。UserDetail為副表,主鍵為UserID,同時作為外鍵與User表產(chǎn)生關聯(lián)。同時,外鍵上設置了級聯(lián)刪除,也就是在刪除User表的紀錄時,會自動刪除UserDetail的紀錄。

對于環(huán)境的描述就到這里,如果您想要自己實驗的話,可以直接使用這些代碼。值得強調一下的是,有些朋友可能會使用NHibernate自動生成數(shù)據(jù)表,那么請注意嚴格調整NHibernate的配置,使其與這個環(huán)境完全相同。

傳統(tǒng)一對一映射

關于一對一映射是否可以延遲加載的問題,我在互聯(lián)網(wǎng)上找了許多資料。有NHibernate的資料,也有沒N的資料。有的資料上說不支持,有的資料卻又說可以實現(xiàn)。不過根據(jù)那些說“可以”的資料進行配置,卻還是無法做到延遲加載。而把這個問題發(fā)到NHibernate的用戶郵件列表中也沒有得到答復。不管怎么樣,我把普通的配置也發(fā)布在這里吧。

  1. <?xml version="1.0" encoding="utf-8" ?> 
  2. <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHTest" namespace="NHTest"> 
  3.   <class name="User" table="`User`"> 
  4.     <id name="UserID" type="Int32" column="UserID"> 
  5.       <generator class="identity" /> 
  6.     </id> 
  7.     <one-to-one name="Detail" class="UserDetail" cascade="save-update" lazy="proxy" /> 
  8.     <property name="Name" type="String" /> 
  9.   </class> 
  10.  
  11.   <class name="UserDetail" table="`UserDetail`" lazy="true"> 
  12.     <id name="UserID" type="Int32" column="UserID"> 
  13.       <generator class="foreign"> 
  14.         <param name="property">User</param> 
  15.       </generator> 
  16.     </id> 
  17.     <one-to-one name="User" class="User" constrained="true" /> 
  18.     <property name="Age" type="Int32" /> 
  19.   </class> 
  20. </hibernate-mapping> 

按照某些資料的說法,我們把one-to-one的lazy設為proxy,并且把UserDetail節(jié)點的lazy設為true,便可以實現(xiàn)延遲加載。也就是說,在執(zhí)行以下代碼時,并不會去獲取UserDetail的內容:

var user = session.Get<User>(1);
可是現(xiàn)在,NHibernate告訴我們現(xiàn)在使用的SQL是這樣子的(您也可以使用SQL Profiler進行觀察):

  1. SELECT  
  2.     user0_.UserID as UserID0_1_,  
  3.     user0_.Name as Name0_1_,  
  4.     userdetail1_.UserID as UserID1_0_,  
  5.     userdetail1_.Age as Age1_0_  
  6. FROM  
  7.     [User] user0_  
  8. left outer join  
  9.     [UserDetail] userdetail1_  
  10.         on user0_.UserID=userdetail1_.UserID  
  11. WHERE  
  12.     user0_.UserID=@p0;  
  13. @p0 = 1 

很明顯,它仍然把UserDetail一并獲取出來了。如果您覺得這里哪里錯了,請告訴我。

開始繞彎路

從現(xiàn)在開始,我們就要走“彎路”了。雖然我們無法在一對一映射的情況下實現(xiàn)延遲加載,但是我們可以輕易做到“一對多”映射時,延遲加載“集合”中的子對象。我們這個workaround的關鍵,便是利用了“一對多”情況下的延遲加載,把“一對一”作為“一對多”的特殊情況進行處理。不過這里就需要我們修改User的Model了:

  1. public class User  
  2. {  
  3.     public virtual int UserID { get; set; }  
  4.     public virtual string Name { get; set; }  
  5.  
  6.     private ISet<UserDetail> m_detailLazyProxySet;  
  7.     private ISet<UserDetail> DetailLazyProxySet  
  8.     {  
  9.         get  
  10.         {  
  11.             if (this.m_detailLazyProxySet == null)  
  12.             {  
  13.                 this.m_detailLazyProxySet = new HashedSet<UserDetail>();  
  14.             }  
  15.  
  16.             return this.m_detailLazyProxySet;  
  17.         }  
  18.         set  
  19.         {  
  20.             this.m_detailLazyProxySet = value;  
  21.         }  
  22.     }  
  23.  
  24.     public virtual UserDetail Detail  
  25.     {  
  26.         get  
  27.         {  
  28.             return this.DetailLazyProxySet.Count <= 0 ? null :  
  29.                 this.DetailLazyProxySet.Single();  
  30.         }  
  31.         set  
  32.         {  
  33.             this.DetailLazyProxySet.Clear();  
  34.             this.DetailLazyProxySet.Add(value);  
  35.         }  
  36.     }  

也多虧NHibernate支持對private屬性的讀寫,我們可以把DetailLazyProxySet設為私有屬性,對外部保持“純潔”——但是,很明顯我們還是污染了Model。因此,這無論如何也只是一個workaround。

如果您使用xml進行配置,這自然沒有什么問題。不過我還是喜歡使用Fluent NHibernate,流暢,方便,還可以導出為xml。因此,我們這里提供Fluent NHibernate的代碼,相信您也可以輕易得出它所對應的xml配置內容:

  1. public class UserMap : ClassMap<User> 
  2. {  
  3.     public UserMap()  
  4.     {  
  5.         Id(u => u.UserID).GeneratedBy.Identity();  
  6.         Map(u => u.Name);  
  7.  
  8.         var paramExpr = Expression.Parameter(typeof(User));  
  9.         var propertyExpr = Expression.Property(paramExpr, "DetailLazyProxySet");  
  10.         var castExpr = Expression.Convert(propertyExpr, typeof(IEnumerable<UserDetail>));  
  11.         var lambdaExpr = Expression.Lambda<Func<User, IEnumerable<UserDetail>>>(castExpr, paramExpr);  
  12.         HasMany(lambdaExpr)  
  13.             .LazyLoad()  
  14.             .AsSet()  
  15.             .KeyColumnNames.Add("UserID")  
  16.             .Cascade.All()  
  17.             .Inverse();  
  18.     }  
  19. }  
  20.  
  21. public class UserDetailMap : ClassMap<UserDetail> 
  22. {  
  23.     public UserDetailMap()  
  24.     {  
  25.         Id(d => d.UserID).GeneratedBy.Foreign("User");  
  26.         Map(d => d.Age);  
  27.         HasOne(d => d.User).Constrained();  
  28.     }  

值得一提的是,由于DetailLazyProxySet是私有的,我們必須手動地構造一個Lambda表達式傳遞給HasMany方法。在實際使用過程中,我們應該提供額外的輔助方法(自然是為ClassMap<T>新增一個擴展方法),并配合約定(屬性名 + LazyProxySet)來進行強類型的編碼定義。它可能是這樣的:

HasOneByProxySet(u => u.Detail)...
嗯,就是這么點代碼。

實驗

打開NHibernate的SQL輸出,并編寫如下代碼:

  1. var user = session.Get<User>(1);  
  2. Console.WriteLine("Name: {0}", user.Name);  
  3. Console.WriteLine("Age: {0}", user.Detail.Age); 

輸出如下:

  1. NHibernate:  
  2.     SELECT  
  3.         user0_.UserID as UserID1_0_,  
  4.         user0_.Name as Name1_0_  
  5.     FROM  
  6.         [User] user0_  
  7.     WHERE  
  8.         user0_.UserID=@p0;  
  9.     @p0 = 1 
  10. ===> Name: Jeffrey Zhao  
  11. NHibernate:  
  12.     SELECT  
  13.         detaillazy0_.UserID as UserID1_,  
  14.         detaillazy0_.UserID as UserID0_0_,  
  15.         detaillazy0_.Age as Age0_0_  
  16.     FROM  
  17.         [UserDetail] detaillazy0_  
  18.     WHERE  
  19.         detaillazy0_.UserID=@p0;  
  20.     @p0 = 1 
  21. ===> Age: 25 

請注意兩條輸出(已標紅)的位置,很明顯現(xiàn)在已經(jīng)實現(xiàn)了延遲加載。那么我們要“饑渴加載(Eager Load)”又當如何?其實也很簡單:

  1. var user = session 
  2.     .CreateCriteria<User>()  
  3.     .SetFetchMode("DetailLazyProxySet", FetchMode.Eager)  
  4.     .Add(Expression.IdEq(8))  
  5.     .UniqueResult<User>();  
  6. Console.WriteLine("===> Name: {0}", user.Name);  
  7. Console.WriteLine("===> Age: {0}", user.Detail.Age); 

同樣,“擴展方法”配合“約定”,我們可以把SetFetchMode這行古怪的代碼改成:

.SetFetchMode(u => u.Detail)...

輸出如下:

  1. NHibernate:  
  2.     SELECT  
  3.         this_.UserID as UserID1_1_,  
  4.         this_.Name as Name1_1_,  
  5.         detaillazy2_.UserID as UserID3_,  
  6.         detaillazy2_.UserID as UserID0_0_,  
  7.         detaillazy2_.Age as Age0_0_  
  8.     FROM  
  9.         [User] this_  
  10.     left outer join  
  11.         [UserDetail] detaillazy2_  
  12.             on this_.UserID=detaillazy2_.UserID  
  13.     WHERE  
  14.         this_.UserID = @p0;  
  15.     @p0 = 8 
  16. ===> Name: Jeffrey Zhao 
  17. ===> Age: 25 

我們的饑渴換來數(shù)據(jù)庫的級聯(lián),和諧而統(tǒng)一。

NHibernate一對一映射的延遲加載總結

至此,我們成功地實現(xiàn)了“一對一”的延遲加載,但是對NHibernate來說,一切都是個一對多的關系。我們獲得了表面的成功,付出了“Model被污染”的代價。

原文來自趙劼博客園博文《NHibernate中一對一關聯(lián)的延遲加載

【編輯推薦】

  1. 微軟發(fā)布NHibernate Linq 1.0 RTM以支持開源
  2. .NET ORM框架NHibernate Linq 1.0發(fā)布
  3. NHibernate與Ado.Net查詢速度的比較
  4. C#.NET使用NHibernate 1.0 XML映射中容易出錯的地方
  5. 淺談LINQ如何插入刪除和更新數(shù)據(jù)庫記錄備注
責任編輯:彭凡 來源: 博客園
相關推薦

2012-03-21 11:43:41

JavaHibernate

2009-06-24 15:49:54

Entity Bean一對一映射

2009-06-03 16:27:27

Hibernate一對一關系

2009-06-04 16:14:22

Hibernate一對Hibernate一對Hibernate多對

2009-06-26 10:15:54

面試HR

2009-06-03 16:18:16

Hibernate關系代碼實例

2009-07-21 17:31:39

iBATIS一對多映射

2009-09-23 10:37:50

Hibernate一對

2012-03-13 16:29:54

Between情侶移動應用

2009-12-23 09:31:11

寬帶路由上網(wǎng)故障

2009-09-24 11:41:46

Hibernate延遲

2012-02-08 13:34:08

HibernateJava

2009-09-23 10:57:02

Hibernate一對

2013-10-12 16:41:01

微軟微軟CEO鮑爾默

2009-10-22 18:24:35

數(shù)字化教學教育

2012-12-14 09:54:31

英特爾數(shù)字化學習年會

2009-06-24 15:51:47

Entity Bean一對多映射

2015-07-30 13:08:56

英特爾一對一數(shù)字化學習

2009-09-22 09:55:58

Hibernate實例

2009-06-04 10:34:19

Hibernate一對一對多關系配置
點贊
收藏

51CTO技術棧公眾號

男捅女免费视频| 动漫黄在线观看| 女海盗2成人h版中文字幕| 国产精品va在线| 老司机一区二区三区| 成人黄色免费| 午夜精品一区二区三区在线 | 国产精品一区二区羞羞答答| 日韩欧美精品在线| 国产成人亚洲综合a∨猫咪| 欧美成人精品在线观看| 国产精品日本| 全部a∨一极品视觉盛宴| 欧美理论片在线| 欧美最新精品| 亚洲丝袜一区在线| gogo久久日韩裸体艺术| 国产精品小说在线| 一区二区三区国产盗摄| 亚洲精品乱码久久久久久蜜桃91| 你懂的在线视频| 亚洲精品一区二区三区婷婷月| 日韩激情毛片| 91视频8mav| 国产精品久久久久国产a级| 欧美亚洲一区在线| 国产精品热视频| 国产精品久久久久免费a∨ | 日韩av不卡在线观看| 青青在线视频一区二区三区| 成人av免费在线观看| 五月激情在线| 亚洲网站视频福利| 亚洲国产二区| 在线观看爽视频| japanese在线视频| 日韩h在线观看| 国产中文字幕精品| 77777少妇光屁股久久一区| 欧美日本一区| 国产精品69久久久| 日韩免费观看高清完整版在线观看| 精品91久久久久| 黄网站色大毛片| 日韩精品在线观看视频| 99re热这里只有精品视频| 看全色黄大色大片免费久久久| 91破解版在线看| 国内精品久久久久影院薰衣草| av在线之家电影网站| 曰韩不卡视频| 5566中文字幕一区二区电影| 日韩高清在线一区| 国产亚洲亚洲国产一二区| 蜜臀av一区二区在线免费观看| 午夜激情在线| 亚洲性图一区二区| 国产在线精品一区二区三区| 日韩欧美亚洲成人| bt7086福利一区国产| 国产一本一道久久香蕉| 三级欧美在线一区| 亚洲午夜精品久久久久久app| 日本美女高清在线观看免费| 精品国产三级电影在线观看| 久久色视频免费观看| 性色一区二区| 中文精品在线| 欧美日韩网址| 一区二区电影在线观看| 欧美激情极品| 亚洲aaa激情| 在线免费观看黄色| 欧美激情精品久久久久久变态| 91精品在线免费观看| 黑人巨大精品欧美一区二区三区 | bt7086福利一区国产| 特黄特色欧美大片| 青草网在线观看| 高清av免费一区中文字幕| 欧美最顶级的aⅴ艳星| 久久久伊人欧美| 91精品国产91| 国产精品91久久久| 国产在线999| 91免费精品国偷自产在线| 国产精品爽黄69天堂a| 国产剧情日韩欧美| 日韩免费在线视频| 亚洲iv一区二区三区| 国产精品久久久久久久久久直播 | 国产真人无码作爱视频免费| 免费看国产一级片| 欧美精品与人动性物交免费看| 国产精彩视频一区二区| 欧美性天天影院| 宅男av一区二区三区| 日本高清视频免费在线观看| 日韩精品欧美在线| 日韩中文字幕在线免费| 1234区在线观看视频免费| avtt天堂资源网站| 欧美黄色小说| 1024在线看片你懂得| 开心久久婷婷综合中文字幕| 亚洲精品一二三**| 欧美日韩精品| 黄色资源网久久资源365| 91碰在线视频| 色综合久久综合网欧美综合网| 欧美一区二区三区色| 欧美精品免费在线| 国产传媒一区二区| www.xxx麻豆| 青青草av免费在线观看| 亚洲天堂av在线| 国产精品羞羞答答在线观看| 老司机精品视频网站| 国产日韩欧美制服另类| 在线看国产一区| 久久偷看各类女兵18女厕嘘嘘| 亚洲自拍偷拍区| 久久久亚洲精品无码| 99免在线观看免费视频高清| 国产亚洲精aa在线看| 国产精品美女久久久浪潮软件| 国产欧美日韩中文久久| 日韩欧美一区二区久久婷婷| 国产成人精品一区二区| 日韩欧美猛交xxxxx无码| 美女看a上一区| 亚洲精品日韩综合观看成人91| 精品sm捆绑视频| 亚洲自拍偷拍色片视频| 美女福利视频在线| 高清在线视频不卡| 女人色偷偷aa久久天堂| 亚洲欧美综合色| 少妇高潮久久久久久潘金莲| 日本免费一区二区三区| 日韩av资源站| 日韩免费一区| 亚洲男人天堂一区| 久久久久国产精品一区| 欧美视频在线观看网站| 网友自拍视频在线| 亚洲精品中文字幕乱码| 一区二区三区影院| 日韩免费在线观看视频| 国产男女在线观看| 久久国产精品美女| 91色婷婷久久久久合中文| yw.139尤物在线精品视频| 欧美日韩午夜爽爽| 亚洲涩涩在线| 麻豆成人久久精品二区三区红| 精品欧美一区二区三区精品久久| 国产精品乱码视频| 69av在线| 精品一区二区三区久久| 日韩精品免费视频| 97中文字幕在线| 国产福利亚洲| 国产午夜一区二区三区| 91av在线视频观看| 中文字幕亚洲精品视频| 国模吧视频一区| 欧美大片一区二区三区| 国产av熟女一区二区三区| 日韩视频网站在线观看| 不卡高清视频专区| 日本精品视频在线| 国产精品久久久久久久龚玥菲| 视频一区二区三区入口| 中文字幕亚洲情99在线| 奇米影音第四色| 91亚洲一区| 亚洲精品一区二区在线| 亚洲国产精品三区| 欧美福利视频| 久久精品欧美视频| 2021国产精品久久精品| 久久精品国产v日韩v亚洲 | 在线免费看av不卡| 福利在线国产| 国产剧情av麻豆香蕉精品| 国产精品久久久久久久7电影| 秋霞在线视频| 国产精品嫩草影院com| 欧洲亚洲一区二区| 亚洲婷婷伊人| 久久精品视频免费播放| 91高清在线| 综合在线观看色| 男插女免费视频| 欧美丰满日韩| 欧美国产日韩xxxxx| 毛片电影在线| 岛国av一区二区三区| 成人免费视频77777|