2009-08-13 139 views
4

我正在設計一個計劃使用NHibernate作爲數據訪問層的OO對象模型。關於多對多關係的OO問題(爲NHibernate計劃)

我想知道在處理兩個彼此具有多對多關係的實體(尤其是與NHibernate輕鬆集成)時最佳的OO設計。

的對象: 用戶 - 單個用戶可以與多個主題 主題 - 一個單一的主題可以與多個用戶

在SQL中,這種關係是直接的使用多對多表;

tblUser 
    userID 

tblSubject 
    subjectID 

tblUserSubject 
    userSubjectID 
    userID 
    subjectID 

那麼,應該如何創建對象?每個對象是否應該包含另一個對象的集合?例如:

class User 
{ 
    public int userID {get; set;} 
    public List<Subject> subjects {get; set;} 
} 

class Subject 
{ 
    public int subjectID {get; set;} 
    public List<User> users {get; set;} 
} 

有沒有更好的方法來建模,使NHibernate可以很容易地堅持關係?

回答

1

找到一篇文章,您可能會對其有幫助。 http://codebetter.com/blogs/peter.van.ooijen/archive/2008/05/29/nhibernate-many-to-many-collections-or-mapping-is-not-one-table-one-class.aspx

總結您的解決方案看起來非常相似。爲了完整起見,這裏是nHibernate映射文件對於User對象的外觀。將nHibernate映射集合用於用戶和主題列表。

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="YourAssemblyName" namespace="YourNamespace"> 
    <class name ="User" table="Users" proxy="User"> 
    <id name="Id" type="Int32" column="idUser"> 
     <generator class="identity"></generator> 
    </id>     
    <many-to-one name="CreatedBy" class="User" column="idUser"></many-to-one> 
    <bag name="subjects" table="tblUserSubject" lazy="false" > 
     <key column="idUser"></key> 
     <many-to-many class="Subject" column="idSubject"></many-to-many> 
    </bag> 
    </class> 
</hibernate-mapping> 

科目是使用表tblUserSubject的包。這個鏈接表的關鍵是idUser(假設這是你的標識列名稱)。多對多的類是我們剛剛映射的Subject類。

0

這應該做的竅門,但取決於你是否真的需要知道哪些用戶可用於主題或主題爲用戶一個propery可能會被排除在外。

3

對於NHibernate最好的設計,我沒有答案,但我想發表評論,因爲這提醒了我很多Rob Conery在關於域驅動設計的Hanselminutes上的討論。

如果您的純粹的用戶在您的主題包含用戶的同時包含主題,我的內心反應是不對的。我想把它縮小到一個或另一個。有趣的是,Conery正在討論他的店面應用以及關於產品是否具有類別或產品是否有類別的爭論。事實證明,既不是就是這種情況 - 它實際上是一種切線關係,最好由應用程序中的服務處理。 (至少,這是實施它的最好的DDD方式,因爲它是他的客戶與實體的關係。)

所以,DDD放在一邊,我不知道它是否會幫助您好好研究一下純真的關係在用戶和主題之間,並且是否一個甚至包含另一個。因爲我不喜歡每個人都含有另一個人的想法,所以我可能會考慮更頻繁地使用哪個子集合。在檢索用戶時,您是否經常使用其主題?相反,雖然主題可能有與之相關的用戶,但是在使用Subject對象時是否經常使用此集合?如果沒有,也許收藏並不直接屬於它。

同樣,我不能證明哪種設計最適合NHibernate,但我認爲這是值得考慮的事情。

0

您已經掌握了支持多對多的基本結構。不要忘了添加方法正確連接了協會:

class User 
{ 
    public int userID {get; set;} 
    public List<Subject> subjects {get; set;} 

    public void AddSubject(Subject subject) 
    { 
     subject.Users.Add(this); 
     this.Subjects.Add(subject); 
    } 
} 

class Subject 
{ 
    public int subjectID {get; set;} 
    public List<User> users {get; set;} 

    public void AddUser(User user) 
    { 
     user.Subjects.Add(this); 
     this.Users.Add(user); 
    } 
} 
0

我發現Kuate等在NHibernate的下列行動今天。 (第60頁和第61頁;我改變了書中的對象名稱以保持原始示例不變。)

這與Vijay的答案類似,但它看起來像NHiberate喜歡看到一個接口,而不是集合的列表類型。

class User 
{ 
    public int userID {get; set;} 
    private ISet subjects = new HashedSet(); 

    public ISet subjects { 
     get { return subjects; } 
     set { subjects = value; } 
    } 

    public void AddSubject(Subject subject) 
    { 
     subject.Users.Add(this); 
     this.Subjects.Add(subject); 
    } 
} 

class Subject 
{ 
    public int subjectID {get; set;} 
    private ISet users = new HashedSet(); 

    public ISet users { 
     get { return users; } 
     set { users = value; } 
    } 

    public void AddUser(User user) 
    { 
     user.Subjects.Add(this); 
     this.Users.Add(user); 
    } 
} 
1

如果User有一個參考他們所有的Subject S的,和Subject他們所有的User S的,那麼當你讀一個單一的用戶,您:

  • 閱讀該用戶的詳細信息;
  • 閱讀該用戶的主題;
  • 閱讀這些主題的每個用戶;
  • 閱讀每個主題的用戶主題;
  • 閱讀這些主題的用戶主題的用戶;
  • [...]

除非你非常小心延遲加載,你可以結束了裝載一大塊兩個表,只是爲了看到一個用戶記錄。

我沒有使用過NHibernate的,但在Java的Hibernate就可以避開這個問題是:使用延遲加載

  • ,或
  • 與更換許多一對多:
    • 兩個新類,UserSummarySubjectSummary,綁定到相同的表,但沒有多到一對一的關係,並
    • 改變User指一堆SubjectSummary s和Subject來引用一堆UserSummary s。