在NHibernate的映射空字符串为NULL(Mapping empty strings to N

2019-06-26 21:47发布

我有一个递归表中的SQL Server数据库:

MyTable:
 ID : string PrimaryKey
 Parent: string references MyTable - NOTNULL !!

并用流利的NHibernate的映射

class MyTable
{
  public virtual string ID {get; set;}
  public virtual MyTable Parent {get; set;}
}

我的问题是,家长应该在我的C#应用​​程序空如果列父为“”(空字符串)数据库中,反之亦然。 不幸的是,我不能改变列式接受NULL!

我试图用IEmptyInterceptor,但我不明白这一点的工作。

在此先感谢,forki

Answer 1:

你需要有主键列,它确实特殊的NULL值处理的IUserType。

public MyTableMap()
{
    Id(x => x.EntryNo)
        // Since the PK is a string, it must be assigned by the application.
        .GeneratedBy.Assigned()
        .SetAttribute("type", typeof(SpecialNullValueStringType).AssemblyQualifiedName);

    References(x => x.Parent);
}

public class SpecialNullValueStringType : IUserType
{
    #region IUserType Members
    public bool IsMutable
    {
        get { return false; }
    }

    public Type ReturnedType
    {
        get { return typeof(string); }
    }

    public SqlType[] SqlTypes
    {
        get { return new[] { NHibernateUtil.String.SqlType }; }
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);

        if (obj == null)
        {
            return null;
        }

        var value = (string) obj;
        if (String.IsNullOrEmpty(value))
        {
            return null;
        }

        return value;
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        if (value == null)
        {
            ((IDataParameter) cmd.Parameters[index]).Value = String.Empty;
        }
        else
        {
            ((IDataParameter) cmd.Parameters[index]).Value = value;
        }
    }

    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)
    {
        if (ReferenceEquals(x, y))
        {
            return true;
        }

        if (x == null || y == null)
        {
            return false;
        }

        return x.Equals(y);
    }

    public int GetHashCode(object x)
    {
        return x == null ? typeof(string).GetHashCode() + 473 : x.GetHashCode();
    }
    #endregion
}


Answer 2:

我发现了一个(乱)的方式来得到这个工作:

public class NullEventListener : IPreUpdateEventListener, IPreInsertEventListener, IPreLoadEventListener
{
    #region IPreInsertEventListener Members

    public bool OnPreInsert(PreInsertEvent preInsertEvent)
    {
        var instance = preInsertEvent.Entity as MyTable;
        if (instance == null)
            return false;

        if (instance.Parent == null)
            Set(preInsertEvent.Persister, preInsertEvent.State, "Parent", string.Empty);     

        return false;
    }

    #endregion

    #region IPreLoadEventListener Members

    public void OnPreLoad(PreLoadEvent preLoadEvent)
    {
        var instance = preLoadEvent.Entity as MyTable;
        if (instance == null)
            return;

        try
        {
            // this is really messy!!
            var parent = Get(preLoadEvent.Persister, preLoadEvent.State, "Parent") as MyTable;
            if (parent == null || parent.ID == "")
                throw new Exception("Set to null");
        }
        catch (Exception)
        {
            Set(preLoadEvent.Persister, preLoadEvent.State, "Parent", null);
        }

        return;
    }

    #endregion

    #region IPreUpdateEventListener Members

    public bool OnPreUpdate(PreUpdateEvent preUpdateEvent)
    {
        var instance = preUpdateEvent.Entity as MyTable;
        if (instance == null)
            return false;

        if (instance.Parent == null)
            Set(preUpdateEvent.Persister, preUpdateEvent.State, "Parent", string.Empty);     

        return false;
    }

    #endregion

    private static void Set(IEntityPersister persister, object[] state, string propertyName, object value)
    {
        int index = Array.IndexOf(persister.PropertyNames, propertyName);
        if (index == -1)
            return;
        state[index] = value;
    }

    private static object Get(IEntityPersister persister, object[] state, string propertyName)
    {
        int index = Array.IndexOf(persister.PropertyNames, propertyName);
        if (index == -1)
            return null;
        return state[index];
    }
}

感谢和问候,forki



Answer 3:

我会去一个IUserType这将转化空字符串null S和反之亦然。 有两种方法要注意是NullSafeGetNullSafeSet

不知道,虽然自定义类型如何与功能NHibernate整合。



Answer 4:

我试图执行IUserType我的映射:

public class MyCustomString : IUserType
{
    public Type ReturnedType
    {
        get { return typeof (MyTable); }
    }

    public SqlType[] SqlTypes
    {
        get { return new[] {NHibernateUtil.String.SqlType}; }
    }    

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        object obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);

        if (obj == null) return null;

        var s = (string) obj;

        if (s == "")
            return null;
        using (ISession session = SessionHelper.OpenSession())
        {
            using (session.BeginTransaction())
            {
                return MyTable.Get(session, s);
            }
        }
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        ((IDataParameter) cmd.Parameters[index]).Value = value == null ? 0 : ((MyTable) value).EntryNo;
    }

   ...
}

并改变了映射

    public MyTableMap()
    {
        Id(x => x.EntryNo);

        Map(x => x.Parent).CustomTypeIs<MyCustomString>();

        // References() doesn't allow CustomTypeIs()
        // References(x => x.Parent).CustomTypeIs<MyCustomString>();
    }

这似乎为我的根的工作 - 但它总是会打开一个会话,以获得正确的父母。 而且这还不是懒 - 所以它总是会检索所有家长到根:-(

这不可能是正确的方式。 我不想打开一个新的会话 - 但除此之外,我返回一个字符串,并获得运行时类型错误。



Answer 5:

你有没有考虑使用空对象模式呢?



文章来源: Mapping empty strings to NULL in NHibernate