Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Nhibernate 建模一对零或一关系(Z基数)_Nhibernate_Oop_Nhibernate Mapping - Fatal编程技术网

Nhibernate 建模一对零或一关系(Z基数)

Nhibernate 建模一对零或一关系(Z基数),nhibernate,oop,nhibernate-mapping,Nhibernate,Oop,Nhibernate Mapping,我正在努力寻找建立1:0,1关系模型的最佳方法(“可能有一个”或“最多有一个”)。我相信这就是所谓的Z基数 例如,假设我有两个类Widget和widgetest。并非所有小部件都经过测试,而且测试是破坏性的,因此每个小部件最多只能有一个WidgetTest。还假设向小部件添加WidgetTest字段是不合适的 我希望我的公共界面是: Widget WidgetTest { get; set; } WidgetTest Widget { get; } 模型1:小部件具有Widg

我正在努力寻找建立1:0,1关系模型的最佳方法(“可能有一个”或“最多有一个”)。我相信这就是所谓的Z基数

例如,假设我有两个类
Widget
widgetest
。并非所有小部件都经过测试,而且测试是破坏性的,因此每个小部件最多只能有一个WidgetTest。还假设向小部件添加WidgetTest字段是不合适的

我希望我的公共界面是:

Widget
    WidgetTest { get; set; }

WidgetTest
    Widget { get; }
模型1:小部件具有WidgetTest属性,并且在数据库中,小部件表具有WidgetTest的唯一约束外键。我的DBA认为这将允许WidgetTest记录在没有小部件的情况下存在

WidgetTable
    WidgetTestId (FK, UQ)
模型2:Widget有一个WidgetTest的私有集合,并通过从由公共WidgetTest属性控制的集合中添加或删除单个对象来强制0,1关系。数据库将其建模为1:m,WidgetTest对小部件具有唯一约束的外键。我认为这意味着采用模型来适应数据库模式(即,我需要做更多的工作)

哪种型号更好?使用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);
            }
         }
     }
}
公共类小部件
{
//这是使用访问策略在NH中映射的
私有IList_widgetests=新列表(1);
公共寡妇
{
获取{return _widgetests.FirstOrDefault();}
设置
{
_widgetests.Clear();
if(值!=null)
{
_widgetests.Add(值);
}
}
}
}
当您说“假设将WidgetTest字段添加到Widget是不合适的”时,您的意思是在域对象中还是在数据库中。如果您希望字段位于数据库中的同一个表中,那么将WidgetTest映射为Widget的一个组件如何?使NHibernate映射文件如下所示:

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

这仍然可以让您拥有指定的公共接口,但是,WidgetTest将成为您可能想要或不想要的值对象。

我的方法是在映射中建模一对多关系,但将“多”约束到单个项。这允许可选的一对一,并且还保证在保存小部件时保存WidgetTest实例。例如:

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;
            }
        }
    }
}
公共类小部件
{
/// 
///NHibernate映射将忽略此属性。
/// 
公共虚拟widgetest widgetest{get;set;}
/// 
///为了使NHibernate更容易持久化,此属性重新打包
///WidgetTest属性作为包含单个项的列表。如果
///试图将此属性设置为包含多个属性的列表
///一个项目,将抛出一个异常。但是为什么要麻烦呢?只需使用
///Widgetest属性。
/// 
公共虚拟IList Widgetests
{
得到
{
IList widgetTests=新列表();
if(this.widgetest!=null)
{
添加(this.widgetest);
}
寡妇归来;
}
设置
{
if(value!=null&&value.Count>1)
{
抛出新异常(“WidgetTests集合不能包含多个项”);
}
else if(value!=null&&value.Count==1)
{
this.widgetest=值[0];
}
其他的
{
this.widgetest=null;
}
}
}
}
我还有两个想法

  • 将表和映射作为组件连接
  • 忽略从属类的Id
可能导致异常“
拥有实体实例不再引用带有cascade=“all delete orphan”的集合”

如果在映射文件中使用
inverse=“true”
cascade=“all delete orphan”
,您会发现这种情况

这是因为nw的答案在每次调用
get
访问器时都会创建一个新列表,并且不会对通过
set
访问器传入的列表执行任何操作。因此,NHibernate没有创建对象时最初传入的
IList
引用,因此无法继续级联

因此,为了解决这个问题,我们需要对
IList
引用进行一些处理,注意不要取消引用它

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;
        }
    }
}
公共类小部件
{
公共小部件()
{
_widgetTests=新列表();
}
/// 
///NHibernate映射将忽略此属性。
/// 
公共widgetest widgetest{get;set;}
/// 
///为了使NHibernate更容易持久化,此属性重新打包
///WidgetTest属性作为包含单个项的列表。如果
///试图将此属性设置为包含多个属性的列表
///一个项目,将抛出一个异常。但是为什么要麻烦呢?只需使用
///Widgetest属性。
/// 
私人寡妇;
受保护的虚拟IList Widgetests
{
得到
{
if(_widgetests.Count==0&&widgetest!=null)
{
_添加(widgetest);
} 
else如果(_widgetests.Count>0&&widgetest==null)
{
_widgetests.Clear();
} 
else if(\u widgetests.Count>0&&widgetest!=\u widgetests[0])
{
_widgetests.Clear();
_添加(widgetest);
}
返回寡妇;
}
设置
{
if(value!=null&&value.Count>1)
{
抛出新异常(“WidgetTest集合不能包含多个项”);
}
if(value!=null&&value.Count==1)
{
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;
            }
        }
    }
}
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;
        }
    }
}
  <class name="Widget" table="widgets">
    ...
    <id name="Id" type="Guid" column="widgetId">
      ...
    </id>
    ...                 
    <bag name="WidgetTests" inverse="true" cascade="all-delete-orphan" access="property">
      ...
      <key column="widgetId" />
      <one-to-many class="WidgetTest" />
    </bag>

  </class>