简体   繁体   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?

Our office team is working and ASP.NET project that uses .NET Framework 4 and NHibernate 3.3.1 我们的办公室团队正在研究使用.NET Framework 4和NHibernate 3.3.1的ASP.NET项目。

I have a POCO domain class called AllResourcesInfo ( which ultimately maps to a Resource table in the database that is inner joined to some other tables, but just to keep things simple, let's just say that the AllResourcesInfo maps to the Resource table ). 我有一个名为AllResourcesInfo的POCO域类(该类最终映射到数据库中的Resource表,该数据库内部连接到其他一些表,但是为了简单起见,我们只说AllResourcesInfo映射到Resource表)。

I also have a POCO domain class called Department ( which ultimately maps to a Department table in the database ) 我也有一个称为Department的POCO域类(该类最终映射到数据库中的Department表)

The AllResourcesInfo could possibly have a many-to-one relationship with a Department. AllResourcesInfo可能与部门有多对一关系。

If an instance of AllResourcesInfo belongs to a department then the AllResourcesInfo.DepartmentDatabaseID has a valid DepartmentDatabaseID that is in the Department entity. 如果AllResourcesInfo的实例属于部门,则AllResourcesInfo.DepartmentDatabaseID具有在Department实体中的有效DepartmentDatabaseID。

However, if the instance of AllResourcesInfo does Not belong to a department then the AllResourcesInfo.DepartmentDatabaseID has a NULL value in the datbase. 但是,如果AllResourcesInfo的实例不属于某个部门,则AllResourcesInfo.DepartmentDatabaseID在数据库中的值为NULL。 database. 数据库。

When I use NHibernate to retrieve( basically NHibernate does a read on the Database ) values from AllResourcesInfo table, NHibernate will populate the C# POCO property of AllResourcesInfo.DepartmentDatabaseID with the 00000000-0000-0000-0000-000000000000 value ( ie the System.Guid.Empty value ) if the AllResourcesInfo does Not belong to a department 当我使用NHibernate从AllResourcesInfo表中检索(基本上是NHibernate对数据库进行读取)值时,NHibernate将使用00000000-0000-0000-0000-0000-000000000000值(即System.Guid)填充AllResourcesInfo.DepartmentDatabaseID的C#POCO属性。 .Empty值)如果AllResourcesInfo不属于部门

However, when I use NHibernate Session to save a brand new C# POCO instance of AllResourcesInfo which does Not belong to any department , I populate the POCO property of AllResourcesInfo.DepartmentDatabaseID with the 00000000-0000-0000-0000-000000000000 value ( ie the System.Guid.Empty value ) But The Database will Obviously Throw an Error Because a Guid value of 00000000-0000-0000-0000-000000000000 obviously fails to exist in Department table of the Database. 但是,当我使用NHibernate Session保存不属于任何部门的全新的AllResourcesInfo的C#POCO实例时,我用00000000-0000-0000-0000-0000-000000000000的值(即系统)填充AllResourcesInfo.DepartmentDatabaseID的POCO属性。 .Guid.Empty值),但数据库显然会引发错误,因为在数据库的Department表中显然不存在Guid值00000000-0000-0000-0000-000000000000。

To summarize, NHibernate Session Save fails to save(or leave ) a uniqueidentifier field in the Database with a value of NULL when we want it to leave a uniqueidentifier field value as null. 总而言之,当我们希望NHibernate Session Save将uniqueidentifier字段值保留为null时,它无法将数据库中的uniqueidentifier字段保存(或保留为NULL)。

Could someone please tell me how we can ensure that NHibernate "translates" a C# POCO Guid property with a value of System.Guid.Empty to be saved( or left) as NULL for the Database uniqueidentifier field value? 有人可以告诉我如何确保NHibernate“转换”具有System.Guid.Empty值的C#POCO Guid属性,以便将数据库uniqueidentifier字段值保存(或保留为NULL)吗?

Guid's cannot be null. Guid不能为null。 You can change your type to Nullable<Guid> , or Guid? 您可以将类型更改为Nullable<Guid>Guid? for short, to allow nulls. 简而言之,允许为空。

You need to implement NHibernate's IUserType. 您需要实现NHibernate的IUserType。

It should like this: 它应该像这样:

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();
    }
}

(Note that I haven't tested it, there are casts here - some tweaking is probably needed) (请注意,我还没有测试过,这里有演员表-可能需要一些调整)

In mapping you specify: 在映射中,您可以指定:

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

What you want to do is create a mapping between Guid (not nullable Guids) and GUIDs in the database. 您要做的是在数据库中的Guid(不可为空的Guid)和GUID之间创建映射。 This is the purpose of the IUserType interface in NHibernate. 这是NHibernate中IUserType接口的目的。 You would need a custom GuidUserType class that does the translation and then refer to it in the mapping definition (hbxml, fluent, whatever). 您将需要一个自定义的GuidUserType类来执行翻译,然后在映射定义中引用它(hbxml,fluent等)。 See http://blog.miraclespain.com/archive/2008/Mar-18.html for a full explanation. 有关完整说明,请参见http://blog.miraclespain.com/archive/2008/Mar-18.html

In the mapping for the primary key of your Department object, there should be a property called unsaved-value. 在Department对象的主键的映射中,应该有一个名为unsaved-value的属性。 Set that to the value of Guid.Empty and all will be fine. 将其设置为Guid.Empty的值,一切都会好的。

Below is an example of how you'd do it using raw hbm mapping: 以下是使用原始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