使 NHibernate “翻译” C# POCO Guid 属性,其值为 System.Guid.Empty,以另存为

本文关键字:Guid System 另存为 Empty 属性 NHibernate 翻译 POCO | 更新日期: 2023-09-27 17:57:09

我们的办公室团队正在 ASP.NET 使用.NET Framework 4和NHibernate 3.3.1的项目

我有一个名为 AllResourcesInfo 的 POCO 域类(它最终映射到数据库中的资源表,该表内部连接到其他一些表,但为了简单起见,我们只是说 AllResourcesInfo 映射到资源表)。

我还有一个名为 Department 的 POCO 域类(它最终映射到数据库中的 Department 表)

AllResourcesInfo可能与一个部门建立多对一的关系。

如果 AllResourcesInfo 的实例属于某个部门,则 AllResourcesInfo.DepartmentDatabaseID 在 Department 实体中具有有效的 DepartmentDatabaseID。

但是,如果 AllResourcesInfo 的实例不属于某个部门,则 AllResourcesInfo.DepartmentDatabaseID 在 datbase. 数据库中具有 NULL 值。

当我使用 NHibernate 从 AllResourcesInfo 表中检索(基本上 NHibernate 对数据库进行读取)值时,如果 AllResourcesInfo 不属于某个部门,NHibernate 将使用

000000000-0000-0000-0000-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000但是,当我使用 NHibernate Session 保存不属于任何部门的 AllResourcesInfo 的全新 C# POCO 实例时,我用 00000000-0000-0000-0000-0000-0000000000000000

值填充 AllResourcesInfo.DepartmentDatabaseID 的 POCO 属性(即 System.Guid.Empty 值) 但是数据库显然会抛出错误,因为 guid 值

00000000-0000-0000-0000000000000 显然无法存在于数据库的部门表中。

总而言之,当我们希望 NHibernate 会话保存将唯一标识符字段值保留为 null 时,无法在数据库中保存(或保留)值为 NULL 的唯一标识符字段。

有人可以告诉我我们如何确保 NHibernate "翻译"具有 System.Guid.Empty 值的 C# POCO Guid 属性以保存(或左)为数据库唯一标识符字段值的 NULL?

使 NHibernate “翻译” C# POCO Guid 属性,其值为 System.Guid.Empty,以另存为

你需要实现 NHibernate 的 IUserType。

它应该是这样的:

using NHibernate.SqlTypes;
using NHibernate.UserTypes;
[Serializable] //to allow NH configuration serialization
public class GuidTypeConverter : IUserType
{
    SqlType[] sqlTypes;
    public GuidTypeConverter()
    {
        sqlTypes = new[] { SqlTypeFactory.GetSqlType(DbType.Guid, 0, 0) };
    }
    public SqlType[] SqlTypes
    {
        get { return sqlTypes; }
    }
    public Type ReturnedType
    {
        get { return typeof(Guid); }
    }
    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        if (rs[names[0]] == DBNull.Value)
        {
            return Guid.Empty;
        }
        return (Guid) rs[names[0]];
    }
    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        var param = (IDataParameter) cmd.Parameters[index];
        param.DbType = sqlTypes[0].DbType;
        var guid = (Guid) value;
        if (guid != Guid.Empty)
        {
            param.Value = guid;    
        }
        else
        {
            param.Value = DBNull.Value;
        }
    }
    public bool IsMutable
    {
        //guid is struct so it's not mutable
        get { return false; }
    }
    public object DeepCopy(object value)
    {
        return value;
    }
    public object Replace(object original, object target, object owner)
    {
        return original;
    }
    public object Assemble(object cached, object owner)
    {
        return cached;
    }
    public object Disassemble(object value)
    {
        return value;
    }
    public new bool Equals(object x, object y)
    {
        return x != null && x.Equals(y); 
    }
    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }
}

(请注意,我还没有测试过它,这里有演员表 - 可能需要一些调整)

在映射中,您可以指定:

<property name="GuidProperty" column="guidColumn"   type="GuidTypeConverterNamespace.GuidTypeConverter, GuidTypeConverterAssemblyName" />

Guid 不能为空。 您可以将类型更改为 Nullable<Guid> 或简称Guid?以允许空值。

您要做的是在数据库中的 Guid(不可为 null 的 Guid)和 GUID 之间创建映射。这就是 NHibernate 中 IUserType 接口的目的。您需要一个自定义的 GuidUserType 类来执行转换,然后在映射定义中引用它(hbxml、fluent 等)。有关完整说明,请参阅 http://blog.miraclespain.com/archive/2008/Mar-18.html。

在 Department 对象的主键映射中,应该有一个名为 unsaved-value 的属性。将其设置为 Guid.Empty 的值,一切都会好起来的。

下面是如何使用原始 hbm 映射执行此操作的示例:

<id name="DepartmentId" type="Guid" unsaved-value="00000000-0000-0000-0000-000000000000">
    <generator class="guid" />
</id>