2012-05-30 44 views
2

...我已經尋找這個問題的「整體」 internetz,它的一個該死的努力之一,其相當複雜的搜索。嘗試搜索「功能NHibernate多對多與額外的列的橋樑表」等...功能NHibernate M2M映射([大]至[許多 - 許多]到[一])

好,使之更容易解釋生病定義一些表可以參考我。 表:用戶,表:函數,表:User_Has_Function。

一個用戶可以有很多功能,並且功能可以有很多用戶,這是在橋牌桌上User_Has_Function鏈接。橋表有額外的列,這隻與關係有關。

不管怎樣,iv發現FNH沒有任何自動解決方案,基本上你必須使用從User到User_Has_Function和從User_Has_Function到Function的一對多關係,因此「[One] to [許多 - 許多]到[一個]「。

我已經在這個環節http://sessionfactory.blogspot.com/2010/12/many-to-many-relationships-with.html解決它像剛剛與FNH類的映射,而不是XML明顯。

但我不是滿意的解決方案,我真的需要做的這一切手動工作,以使該功能正常嗎?同樣,現在它將在橋表中插入重複項。

在我的腦海裏我做錯了什麼,因爲我無法想象有沒有這方面的支持。只需使用SaveAndUpdate(),不插入重複項,當我刪除實體時,關係也被刪除,如果沒有關係,則刪除實體本身等。流利NHibernate所以不要大聲嚷嚷,如果我做了一些非常錯誤的事情。 :)

實體:

public class XUser 
{ 
    public virtual int Id { get; set; } 
    ... 
    public virtual IList<XUserHasXFunction> XUserHasXFunctions { get; set; } 

    public XUser() 
    { 
     XUserHasXFunctions = new List<XUserHasXFunction>(); 
    } 

    public virtual void AddXFunction(XFunction xFunction, int isActive) 
    { 
     var xUserHasXFunction = new XUserHasXFunction() 
            { 
             XUser = this, 
             XFunction = xFunction, 
             DeployedDate = DateTime.Now 
            }; 
     XUserHasXFunctions.Add(xUserHasXFunction); 
     xFunction.XUserHasXFunctions.Add(xUserHasXFunction); 
    } 

    public virtual void RemoveXFunction(XFunction xFunction) 
    { 
     var xUserHasXFunction = XUserHasXFunctions.Single(x => x.XFunction == xFunction); 
     XUserHasXFunctions.Remove(xUserHasXFunction); 
     xFunction.XUserHasXFunctions.Remove(xUserHasXFunction); 
    } 
} 

public class XFunction 
{ 
    public virtual int Id { get; set; } 
    ... 
    public virtual IList<XUserHasXFunction> XUserHasXFunctions { get; set; } 

    public XFunction() 
    { 
     XUserHasXFunctions = new List<XUserHasXFunction>(); 
    } 

    public virtual void AddXUser(XUser xUser, int isActive) 
    { 
     var xUserHasXFunction = new XUserHasXFunction() 
            { 
             XUser = xUser, 
             XFunction = this, 
             DeployedDate = DateTime.Now 
            }; 
     XUserHasXFunctions.Add(xUserHasXFunction); 
     xUser.XUserHasXFunctions.Add(xUserHasXFunction); 
    } 

    public virtual void RemoveXUser(XUser xUser) 
    { 
     var xUserHasXFunction = XUserHasXFunctions.Single(x => x.XUser == xUser); 
     XUserHasXFunctions.Remove(xUserHasXFunction); 
     xUser.XUserHasXFunctions.Remove(xUserHasXFunction); 
    } 
} 

public class XUserHasXFunction 
{ 
    public virtual int Id { get; set; } 
    public virtual XUser XUser { get; set; } 
    public virtual XFunction XFunction { get; set; } 
    public virtual DateTime DeployedDate { get; set; } 
} 

映射:

public class XUserMap : ClassMap<XUser> 
{ 
    public XUserMap() 
    { 
     Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID"); 
     Table("XUSER"); 
     ... 
     HasMany(x => x.XUserHasXFunctions).Cascade.All(); 
    } 
} 

public class XFunctionMap : ClassMap<XFunction> 
{ 
    public XFunctionMap() 
    { 
     Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID"); 
     Table("XFUNCTION"); 
     ... 
     HasMany(x => x.XUserHasXFunctions).Cascade.All(); 
    } 
} 

public class XUserHasXFunctionMap : ClassMap<XUserHasXFunction> 
{ 
    public XUserHasXFunctionMap() 
    { 
     Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID"); 
     Table("USER_HAS_FUNCTION"); 
     Map(x => x.DeployedDate, "DEPLOYED_DATE"); 

     References(x => x.XUser).ForeignKey("XUSER_ID").Cascade.SaveUpdate(); 
     References(x => x.XFunction).ForeignKey("XFUNCTION_ID").Cascade.SaveUpdate(); 
    } 
} 
+0

好代碼,你希望別人看到代碼,你把它放在他們面臨炫耀你輝煌。我寫的代碼解決了這個問題,id從來沒有向任何人展示過,這就是我的感受......而且這不是你應該寫代碼的方式,這是不好的做法。 – furier

回答

0

我結束了使用一個ISet,而不是在ILists中的關係。 ISet不允許重複,但IList的確如此。要使用ISet,必須覆蓋存儲在ISet中的對象的Equals和GetHashCode方法。

我從XUser和XFunction級聯而不是其他方式,結果是當我因爲級聯而刪除了一個實體時,所有3個表中的每個記錄都被刪除了。

這是我如何解決它。

實體:

public class XUser 
{ 
    public virtual int Id { get; set; } 
    ... 
    public virtual ISet<XUserHasXFunction> XUserHasXFunctions { get; set; } 

    public XUser() 
    { 
     XUserHasXFunctions = new HashedSet<XUserHasXFunction>(); 
    } 

    public virtual void AddXFunction(XFunction xFunction, int isActive) 
    { 
     var xUserHasXFunction = new XUserHasXFunction() 
            { 
             XUser = this, 
             XFunction = xFunction, 
             IsActive = isActive, 
             DeployedDate = DateTime.Now 
            }; 
     if (XUserHasXFunctions.Contains(xUserHasXFunction) && xFunction.XUserHasXFunctions.Contains(xUserHasXFunction)) 
     { 
      return; 
     } 
     XUserHasXFunctions.Add(xUserHasXFunction); 
     xFunction.XUserHasXFunctions.Add(xUserHasXFunction); 
    } 

    public virtual void RemoveXFunction(XFunction xFunction) 
    { 
     var xUserHasXFunction = XUserHasXFunctions.Single(x => x.XFunction == xFunction); 
     XUserHasXFunctions.Remove(xUserHasXFunction); 
     xFunction.XUserHasXFunctions.Remove(xUserHasXFunction); 
    } 
} 

public class XFunction 
{ 
    public virtual int Id { get; set; } 
    ... 
    public virtual ISet<XUserHasXFunction> XUserHasXFunctions { get; set; } 

    public XFunction() 
    { 
     XUserHasXFunctions = new HashedSet<XUserHasXFunction>(); 
    } 

    public virtual void AddXUser(XUser xUser, int isActive) 
    { 
     var xUserHasXFunction = new XUserHasXFunction() 
            { 
             XUser = xUser, 
             XFunction = this, 
             IsActive = isActive, 
             DeployedDate = DateTime.Now 
            }; 
     if (XUserHasXFunctions.Contains(xUserHasXFunction) && xUser.XUserHasXFunctions.Contains(xUserHasXFunction)) 
     { 
      return; 
     } 
     XUserHasXFunctions.Add(xUserHasXFunction); 
     xUser.XUserHasXFunctions.Add(xUserHasXFunction); 
    } 

    public virtual void RemoveXUser(XUser xUser) 
    { 
     var xUserHasXFunction = XUserHasXFunctions.Single(x => x.XUser == xUser); 
     XUserHasXFunctions.Remove(xUserHasXFunction); 
     xUser.XUserHasXFunctions.Remove(xUserHasXFunction); 
    } 
} 

public class XUserHasXFunction 
{ 
    public virtual int Id { get; set; } 
    ... 
    public virtual DateTime DeployedDate { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
      return false; 
     var t = obj as XUserHasXFunction; 
     if (t == null) 
      return false; 
     return XUser == t.XUser && XFunction == t.XFunction; 
    } 

    public override int GetHashCode() 
    { 
     return (XUser.Id + "|" + XFunction.Id).GetHashCode(); 
    } 
} 

映射:

public class XUserMap : ClassMap<XUser> 
{ 
    public XUserMap() 
    { 
     Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID"); 
     Table("XUSER"); 
     ... 
     HasMany(x => x.XUserHasXFunctions).KeyColumn("XUSER_ID").Cascade.All(); 
    } 
} 

public class XFunctionMap : ClassMap<XFunction> 
{ 
    public XFunctionMap() 
    { 
     Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID"); 
     Table("XFUNCTION"); 
     ... 
     HasMany(x => x.XUserHasXFunctions)KeyColumn("XFUNCTION_ID").Cascade.All(); 
    } 
} 

public class XUserHasXFunctionMap : ClassMap<XUserHasXFunction> 
{ 
    public XUserHasXFunctionMap() 
    { 
     Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID"); 
     Table("XUSER_HAS_XFUNCTION"); 
     ... 
     Map(x => x.DeployedDate, "DEPLOYED_DATE"); 

     References(x => x.XUser).Column("XUSER_ID"); 
     References(x => x.XFunction).Column("XFUNCTION_ID"); 
    } 
} 

用法:

To add relations. 
xFunction.AddXUser(xUser, isActive); //visa versa if you like to add a function to a user... 
dao.Store(xFunction); //to actually add the relation in the db 

now to remove relation 
xFunction.RemoveXUser(xUser); //Realtion is removed but neither of the objects xFunction or xUser 
dao.Store(xFunction); //...same 

to remove a user and its relations. 
dao.delete(xUser); //but the xFunction object it was connected to is not removed 
//if you want the xFunction object to be removed you have to do that manually. 
0

我結束了與用戶,用戶組,USER_GROUP做類似的事情一段時間了,最​​後不得不使用具有的哈克方法兩個對象都存在於雙方,也可以手動選擇保存或更新。

我不認爲有一個NICE辦法做你想做的事,我同意它是從數據庫的角度來看是相當合乎邏輯的事情,但從建模的角度來看是一個疼痛。

正如我還假設您有使用組合鍵爲您user_has_function表,以確保你可以有多個功能,爲多個用戶。我認爲大多數人試圖避免並最終使用代理鍵或其他方法。

我知道這不是一個答案,但我從來沒有找到一個真實當我發佈它的同一個問題的答案。

這裏有一個類似的問題我貼了一段時間後:

Nhibernate composite key question

+0

感謝您的回答,我開始看到這個問題沒有「最佳實踐」,您只是解決它,讓它成爲......我討厭這樣的解決方案,讓我想扭轉我的皮膚:P – furier

1

我不明白「我真的需要做的這一切體力勞動」的一部分。什麼「所有這些手冊工作」?這裏沒有什麼特別的。映射很簡單,並且c#代碼不需要執行任何持久化操作,這是普通的舊OO設計。

如果您得到重複的行,您的映射有問題。這可能是因爲沒有被映射爲逆的反向收集。

如果您不需要從功能導航到用戶,這很容易。將關係映射爲實體(如博客中所述),或者甚至更簡單,將其映射爲複合元素。

(對不起,我不知道流利)

<bag name="Functions" table="User_Has_Function"> 
    <key column="UserId" /> 
    <composite-element> 
    <many-to-one class="Function"/> 
    </composite-element> 
</bag> 

編輯:

從評論:

我談論的做工手動獲取並檢查 以從用戶或功能中刪除和添加關係。

您是否在談論所需的添加和刪除方法,它們保持關係的一致性?這是簡單的OO設計。如果你不是NHibernate的話,你必須寫完全一樣的(給定相同的類模型)。

刪除功能的用戶使這一切的方式級聯到用戶和 等等...

號刪除,級聯當一個對象被刪除發生。當你刪除一個用戶時,你應該級聯user_has_function。從那裏,你可能會或可能不會級聯這些功能。在另一個方向相同。還有「cascade-all-delete-orphans」的概念。這意味着,除了常規級聯之外,從集合中刪除對象時會自動刪除一個對象。這不是級聯的。這是一種非常基本的垃圾收集。如果你想在你的情況下使用它,你不應該將它應用於user-> user_has_function集合和function-> user_has_function集合,因爲它會嘗試刪除對象兩次。

不要忘記映射兩個集合逆。如果你不這樣做,你可能會得到重複的條目。

確保三個映射(user-> user_has_function集合,function-> user_has_function和user_has_function類映射)使用相同的表名稱和外鍵名稱。

你不需要混淆組合鍵。

+0

The我正在談論的手動工作是手動獲取和檢查以從用戶或功能中刪除和添加關係。從一個函數中刪除一個用戶使其級聯到用戶等等... 也許我對這一切的理解只是明顯錯誤,或者我正在做一些根本性的錯誤,但這就是爲什麼我問這是「唯一」的方式,或有人可以指引我採取正確的方向來實現最佳做法。 – furier

+0

發現此鏈接關於複合鍵也http://devlicio.us/blogs/anne_epstein/archive/2009/11/20/nhibernate-and-composite-keys.aspx – furier

+0

我已經添加了另一節。 –