2010-02-05 50 views
8

我在努力尋找模型1:0,1關係(「可能有一個」或「至多有一個」)的最佳方法。我相信這就是所謂的Z基數。建模一到零或一個關係(Z基數)

例如,假設我有兩個類WidgetWidgetTest。並非所有的Widget都經過測試,測試具有破壞性,因此每個Widget最多隻能有一個WidgetTest。還假定將WidgetTest字段添加到Widget是不合適的。

我想我的公共接口爲:

Widget 
    WidgetTest { get; set; } 

WidgetTest 
    Widget { get; } 

模型1:小部件有一個WidgetTest財產,並在數據庫中的窗口小部件表有唯一約束外鍵WidgetTest。我的DBA認爲這將允許WidgetTest記錄在沒有Widget的情況下存在。

WidgetTable 
    WidgetTestId (FK, UQ) 

模型2:窗口小部件具有WidgetTest的專用集合,並執行通過添加或刪除從由公共WidgetTest屬性控制集合的單個對象的0,1的關係。數據庫使用WidgetTest將1:m模型化爲具有唯一約束外鍵的Widget。我認爲這意味着採用模型來適應數據庫模式(即爲我工作更多)。

WidgetTestTable 
    WidgetId (FK, UQ) 

哪種型號比較好?用NHibernate更容易實現?還是有第三種方式?

編輯...這是我結束了:

public class Widget 
{ 
    // This is mapped in NH using a access strategy 
    private IList<WidgetTest> _widgetTests = new List<WidgetTest>(1); 

    public WidgetTest 
    { 
     get { return _widgetTests.FirstOrDefault(); } 
     set 
     { 
      _widgetTests.Clear(); 
      if (value != null) 
      { 
       _widgetTests.Add(value); 
      } 
     } 
    } 
} 
+0

什麼是錯用1 :?由PK-PK強制執行。映射,相當直線前方。 – 2010-02-08 14:33:02

回答

4

我的方法是模擬映射中的一對多關係,但將「多」限制爲單個項目。這允許可選的一對一,並且保證WidgetTest實例在保存Widget時保持不變。例如:

public class Widget 
{ 
    /// <summary> 
    /// This property is ignored by the NHibernate mappings. 
    /// </summary> 
    public virtual WidgetTest WidgetTest { get; set; } 

    /// <summary> 
    /// For easier persistence with NHibernate, this property repackages the 
    /// WidgetTest property as a list containing a single item. If an 
    /// attempt is made to set this property to a list containing more than 
    /// one item, an exception will be thrown. But why bother? Just use the 
    /// WidgetTest property. 
    /// </summary> 
    public virtual IList<WidgetTest> WidgetTests 
    { 
     get 
     { 
      IList<WidgetTest> widgetTests = new List<WidgetTest>(); 
      if (this.WidgetTest != null) 
      { 
       widgetTests.Add(this.WidgetTest); 
      } 
      return widgetTests; 
     } 
     set 
     { 
      if (value != null && value.Count > 1) 
      { 
       throw new Exception("The WidgetTests collection may not contain more than one item."); 
      } 
      else if (value != null && value.Count == 1) 
      { 
       this.WidgetTest = value[0]; 
      } 
      else 
      { 
       this.WidgetTest = null; 
      } 
     } 
    } 
} 
+0

這或多或少是我的「模特2」,過去我也做過類似的事情。我把這個集合映射爲私有成員,但是不要公開它。我正在考慮更多,這種模式適用於1:n的關係。當n = 1時,我會掛上電話。 – 2010-02-05 22:51:28

+0

請參閱編輯我的問題以獲得我解決的解決方案。這個答案是最接近的,所以我接受了。 – 2010-02-06 15:47:24

+0

我喜歡你的變化......非常簡潔。你願意分享你使用的NH地圖嗎? – 2010-02-06 21:30:30

1

當你說「認爲這是不合適的添加WidgetTest字段部件」,你在你的域對象或數據庫中的意思。如果您對字段位於數據庫的同一個表中感到滿意,那麼如何將WidgetTest映射爲Widget的組件?有NHibernate的映射文件的樣子:

<class name="Widget" table="Widget"> 
    ... 
    <property name="WidgetProperty"/> 
    ... 
    <component name="WidgetTest" class="WidgetTest"> 
     <property name="WidgetTestProperty"/> 
    </component> 
</class> 

給表結構:

WidgetTable 
    WidgetProperty 
    WidgetTestProperty 

這仍讓你有你所指定的公共接口,但是,WidgetTest將成爲一個值對象,你可能會或可能不想要。

+0

我的意思是在表中。除了添加超過一百個額外的字段,他們將不得不默認爲null,這是不希望的。我對模型1:0,1關係模型的最佳方式比對特定應用程序更感興趣。 – 2010-02-05 17:15:53

0

我有其他的2個想法here

  • 加入表和圖作成分
  • 忽略依賴類的標識
0

answer given by nw.會導致異常「 A collection with cascade=」all-delete-orphan」 was no longer referenced by the owning entity instance「。

如果您在映射文件中使用inverse="true"cascade="all-delete-orphan",則會發現這種情況。

這是因爲nw。的答案在每次調用get訪問器時都會創建一個新列表,並且不會對通過set訪問器傳入的列表執行任何操作。因此,NHibernate沒有創建對象時最初傳入的IList<WidgetTest>引用,並且無法繼續執行級聯。

所以爲了解決這個問題,我們需要用IList<WidgetTest>參考做一些事情,並小心不要去參考它。

public class Widget 
{ 
    public Widget() 
    { 
     _widgetTests = new List<WidgetTest>(); 
    } 

    /// <summary> 
    /// This property is ignored by the NHibernate mappings. 
    /// </summary> 
    public WidgetTest WidgetTest { get; set; } 

    /// <summary> 
    /// For easier persistence with NHibernate, this property repackages the 
    /// WidgetTest property as a list containing a single item. If an 
    /// attempt is made to set this property to a list containing more than 
    /// one item, an exception will be thrown. But why bother? Just use the 
    /// WidgetTest property. 
    /// </summary> 
    private IList<WidgetTest> _widgetTests; 
    protected virtual IList<WidgetTest> WidgetTests 
    { 
     get 
     { 
      if (_widgetTests.Count == 0 && WidgetTest != null) 
      { 
       _widgetTests.Add(WidgetTest); 
      } 
      else if (_widgetTests.Count > 0 && WidgetTest == null) 
      { 
       _widgetTests.Clear(); 
      } 
      else if (_widgetTests.Count > 0 && WidgetTest != _widgetTests[0]) 
      { 
       _widgetTests.Clear(); 
       _widgetTests.Add(WidgetTest); 
      } 
      return _widgetTests; 
     } 
     set 
     { 
      if (value != null && value.Count > 1) 
      { 
       throw new Exception("The WidgetTest collection may not contain more than one item."); 
      } 
      if (value != null && value.Count == 1) 
      { 
       WidgetTest = value[0]; 
      } 
      else 
      { 
       WidgetTest = null; 
      } 

      //Store the reference 
      _widgetTests = value; 
     } 
    } 
} 

映射:

​​3210

靈感的增強:

http://www.onkarjoshi.com/blog/188/hibernateexception-a-collection-with-cascade-all-delete-orphan-was-no-longer-referenced-by-the-owning-entity-instance/comment-page-1/