我有一个递归表中的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
你需要有主键列,它确实特殊的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
}
我发现了一个(乱)的方式来得到这个工作:
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
我会去一个IUserType
这将转化空字符串null
S和反之亦然。 有两种方法要注意是NullSafeGet
和NullSafeSet
。
不知道,虽然自定义类型如何与功能NHibernate整合。
我试图执行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>();
}
这似乎为我的根的工作 - 但它总是会打开一个会话,以获得正确的父母。 而且这还不是懒 - 所以它总是会检索所有家长到根:-(
这不可能是正确的方式。 我不想打开一个新的会话 - 但除此之外,我返回一个字符串,并获得运行时类型错误。