NHibernate 多对一映射:如果父级为 null,则将外键设置为空 Guid 而不是 null

2024-03-06

我想要做的事情确实非常简单,但我似乎无法使用 NHibernate 进行正确的映射。

我正在处理一个包含父对象和子对象的数据库。子对象具有对数据类型 Guid 的父对象主键的外键引用。无论如何都很正常。现在数据库的设置方式是外键字段不能为空,因此对于没有父对象的孤立对象,外键应该是一个空的 Guid ('00000000-0000-0000-0000-000000000000 ')。

我设置 Nhibernate 的方式长期以来一直运行良好,但最近我将关系设为双向,然后问题开始出现。显然,NHibernate 会看到父级为 null 并尝试将 null 保存到外键字段,但这是不允许的!

我使用的关系映射的结构示例如下。

父端映射:

<id name="ID" column="ID">
    <generator class="guid" />
</id>
<bag name="Children" table="Children" lazy="false" cascade="all" inverse="true">
  <key column="FK_OwnerID" not-null="true"/>
  <one-to-many class="Childclass"/>
</bag>

子端映射:

<many-to-one name="Owner" column="FK_OwnerID" not-found="ignore" not-null="false" class="OwnerClass"/>

我一直在尝试不同的属性,但没有成功。我是否被迫使用 insert="false" 和 update="false" 属性,如果是这样,我如何准确维护这些关系?

预先感谢您的任何帮助。


如果我理解正确的话,你的数据库结构并没有强制执行引用完整性(FK_OwnerID 并不是真正的外键),但是通过你对映射的更改,你告诉 NHibernate 强制执行这一点。我认为这是行不通的。

基本上,我看到两个选项可以解决这个问题:

  1. 使用您的创建一个虚拟条目 000-DB 中的 Guid 充当 所有这些孤儿的父母。
  2. 更改表以允许该列中存在 NULL 并 使其成为真正的外键 约束(带有“级联集 无效的)。 (我会推荐这样做。)

Edit:如果选项 1 不可行,那么我建议选项 3: 您可以尝试 NHibernate 的拦截器功能。您需要实现 IInterceptor (或继承自 EmptyInterceptor)。 OnSave() 方法用于新对象,OnFlushDirty 用于更改对象。我们在这里所做的是创建一个具有所需 ID 的新“虚拟”对象并分配它。

using System;
using NHibernate;

namespace NameSpaceWithDAL
{
    public class TestInterceptor : NHibernate.EmptyInterceptor
    {
        public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
        {
            if (entity is ChildClass && (entity as ChildClass).Owner == null)
            {
                SetState(propertyNames, state, "Owner", new OwnerClass { ID = "000..." });
            }

            return true;
        }    

        public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types)
        {
            if (entity is ChildClass && (entity as ChildClass).Owner == null)
            {
                SetState(propertyNames, state, "Owner", new OwnerClass { ID = "000..." });
            }

            return true;
        }

        private void SetState(string[] propertyNames, object[] state, string propertyname, object value)
        {
            var index = Array.IndexOf(propertyNames, propertyname);
            if (index == -1) return;
            state[index] = value;
        }    
    }
}

为了使用它,需要为会话(在 OpenSession() 中)或整体配置中定义拦截器:

new Configuration().SetInterceptor(new TestInterceptor());

我用简单的属性测试了上面的代码,所以我不能说这是否真的适用于关系。

代码示例取自迈克·奥布莱恩 http://blog.mikeobrien.net/2010/01/automatically-setting-modified-and.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NHibernate 多对一映射:如果父级为 null,则将外键设置为空 Guid 而不是 null 的相关文章

随机推荐