2010-02-05 61 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/

相关问题