NHibernate,将DB中的空引用值保存为0(零)
本文关键字:保存 引用 DB NHibernate | 更新日期: 2023-09-27 18:27:34
我发现了一个tuplizer的例子,它可以在保存null关系时保存0。这是必要的,因为我正在开发一个应用程序的遗留数据库模式。
我在这里尝试了tuplizer:http://nhforge.org/blogs/nhibernate/archive/2011/01/28/how-to-use-0-instead-of-null-for-foreign-keys.aspx
在那个例子中,我得到了ProxyFactory的一个nullreferenceexception。然后我在这里找到了代码的更新:https://bitbucket.org/jfromaniello/hotgazpachoeg/changeset/87ac41c473ae
然而,这对我也不起作用。在最后一个方法SetPropertyValues(被描述为dirty hack 3,在从DB读取对象时使用)中,我在读取一个不相关的对象(而不是Sample)时,在这部分得到了一个nullref异常
我的映射如下(简化):
Table("ej_sample");
Not.LazyLoad();
Id(s => s.Id, "sampleID").GeneratedBy.Native();
References<Sample>(s => s.ParentSample, "parentSampleID").NotFound.Ignore();
当不存在此类对象时,parentSampleID列必须为0。
我想,我只需要在插入和更新上做一些肮脏的黑客操作(在我的情况下可能只有插入)。
插入时,我想创建一个假代理,但[2]中的代码从数据库加载实体(可能使用Null对象?!)。
插入脏破解:
public override object[] GetPropertyValuesToInsert(object entity, IDictionary mergeMap, ISessionImplementor session) {
var values = base.GetPropertyValuesToInsert(entity, mergeMap, session);
//dirty hack 1
for(int i = 0; i < values.Length; i++) {
if(values[i] == null && typeof(IEntity).IsAssignableFrom(getters[i].ReturnType)) {
values[i] = ((ISession)session).Load(getters[i].ReturnType, 0);
}
}
return values;
}
我试着创建一个假的代理,而不是做上面的事情:
public override object[] GetPropertyValuesToInsert(object entity, IDictionary mergeMap, ISessionImplementor session) {
var values = base.GetPropertyValuesToInsert(entity, mergeMap, session);
//dirty hack 1
for(int i = 0; i < values.Length; i++) {
if(values[i] == null && typeof(IEntity).IsAssignableFrom(getters[i].ReturnType)) {
//values[i] = ((ISession)session).Load(getters[i].ReturnType, 0);
values[i] = CreateFakeProxy(i);
}
}
return values;
}
private object CreateFakeProxy(int i) {
object proxy;
using(var sessionImplementor = _sessionFactory.OpenSession()) {
proxy = _sessionFactory
.GetEntityPersister(getters[i].ReturnType.FullName)
.CreateProxy(0, (ISessionImplementor)sessionImplementor);
}
return proxy;
}
然后,我在_sessionfactory上得到一个nullref异常,该异常设置在ctor:中
private readonly ISessionFactoryImplementor _sessionFactory;
public NullableTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity)
: base(entityMetamodel, mappedEntity) {
_sessionFactory = entityMetamodel.SessionFactory;
}
有什么想法可以做到这一点吗?
简单的解决方案是添加以下预插入和预更新侦听器。
public class NullToZeroEventListener : AuditEventListener, IPreInsertEventListener, IPreUpdateEventListener
{
public bool OnPreInsert(PreInsertEvent @event) {
ZeroNullIds(@event.State, @event.Persister.PropertyNames);
return false;
}
public bool OnPreUpdate(PreUpdateEvent @event) {
ZeroNullIds(@event.State, @event.Persister.PropertyNames);
return false;
}
protected internal void ZeroNullIds(Object[] state, string[] propertyNames) {
for(int i = 0; i < propertyNames.Length; i++) {
if(state[i] != null || propertyNames[i].EndsWith("ID")) continue;
state[i] = 0;
}
}
}
在映射中,请确保忽略0个ID,例如:References<User>(s => s.User, "userID").NotFound.Ignore().LazyLoad();
在您的会话工厂中,为预插入和预更新事件添加一个侦听器(首先显示在此处):
.ExposeConfiguration(c =>
{
if(!c.EventListeners.PreInsertEventListeners.Any()) {
c.AppendListeners(ListenerType.PreInsert, new IPreInsertEventListener[] { new NullToZeroEventListener() });
}
});