繁体   English   中英

使NHibernate使用System.Guid.Empty值“转换” C#POCO Guid属性以将其作为Database uniqueidentifier字段保存为NULL?

[英]Making NHibernate “translate” C# POCO Guid property with value of System.Guid.Empty to be saved as NULL for the Database uniqueidentifier field?

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

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

我也有一个称为Department的POCO域类(该类最终映射到数据库中的Department表)

AllResourcesInfo可能与部门有多对一关系。

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

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

当我使用NHibernate从AllResourcesInfo表中检索(基本上是NHibernate对数据库进行读取)值时,NHibernate将使用00000000-0000-0000-0000-0000-000000000000值(即System.Guid)填充AllResourcesInfo.DepartmentDatabaseID的C#POCO属性。 .Empty值)如果AllResourcesInfo不属于部门

但是,当我使用NHibernate Session保存不属于任何部门的全新的AllResourcesInfo的C#POCO实例时,我用00000000-0000-0000-0000-0000-000000000000的值(即系统)填充AllResourcesInfo.DepartmentDatabaseID的POCO属性。 .Guid.Empty值),但数据库显然会引发错误,因为在数据库的Department表中显然不存在Guid值00000000-0000-0000-0000-000000000000。

总而言之,当我们希望NHibernate Session Save将uniqueidentifier字段值保留为null时,它无法将数据库中的uniqueidentifier字段保存(或保留为NULL)。

有人可以告诉我如何确保NHibernate“转换”具有System.Guid.Empty值的C#POCO Guid属性,以便将数据库uniqueidentifier字段值保存(或保留为NULL)吗?

Guid不能为null。 您可以将类型更改为Nullable<Guid>Guid? 简而言之,允许为空。

您需要实现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(不可为空的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>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM