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

StackOverflow https://stackoverflow.com/questions/14654364

Domanda

Our office team is working and ASP.NET project that uses .NET Framework 4 and NHibernate 3.3.1

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 ).

I also have a POCO domain class called Department ( which ultimately maps to a Department table in the database )

The AllResourcesInfo could possibly have a many-to-one relationship with a Department.

If an instance of AllResourcesInfo belongs to a department then the AllResourcesInfo.DepartmentDatabaseID has a valid DepartmentDatabaseID that is in the Department entity.

However, if the instance of AllResourcesInfo does Not belong to a department then the AllResourcesInfo.DepartmentDatabaseID has a NULL value in the datbase. 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

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.

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.

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?

È stato utile?

Soluzione

You need to implement NHibernate's 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" />

Altri suggerimenti

Guid's cannot be null. You can change your type to Nullable<Guid>, or Guid? for short, to allow nulls.

What you want to do is create a mapping between Guid (not nullable Guids) and GUIDs in the database. This is the purpose of the IUserType interface in NHibernate. You would need a custom GuidUserType class that does the translation and then refer to it in the mapping definition (hbxml, fluent, whatever). See http://blog.miraclespain.com/archive/2008/Mar-18.html for a full explanation.

In the mapping for the primary key of your Department object, there should be a property called unsaved-value. Set that to the value of Guid.Empty and all will be fine.

Below is an example of how you'd do it using raw hbm mapping:

<id name="DepartmentId" type="Guid" unsaved-value="00000000-0000-0000-0000-000000000000">
    <generator class="guid" />
</id>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top