【问题标题】:NHibernate, save null reference value in DB as 0 (zero)NHibernate,将空引用值在 DB 中保存为 0(零)
【发布时间】:2012-07-11 21:42:40
【问题描述】:

我发现这个 tuplizer 示例在保存空关系时保存 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(描述​​为脏 hack 3,在从 DB 读取对象时使用)中,当读取不相关的对象(不是示例)时,我在这部分遇到 nullref 异常 if(typeof(IEntity) /p>

我的映射如下(简化):

   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;

    }

任何想法如何做到这一点?

【问题讨论】:

  • 您将不相关的ISession 转换为ISessionImplementor。更安全的是session.GetSessionImplementor()

标签: c# nhibernate legacy-database tuplizer


【解决方案1】:

简单的解决方案是添加以下 preinsert 和 preupdate 监听器。

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&lt;User&gt;(s =&gt; s.User, "userID").NotFound.Ignore().LazyLoad();

在您的 sessionfactory 中,为 preinsert 和 preupdate 事件添加一个监听器(这里首先显示):

           .ExposeConfiguration(c =>
            {
                if(!c.EventListeners.PreInsertEventListeners.Any()) {
                    c.AppendListeners(ListenerType.PreInsert, new IPreInsertEventListener[] { new NullToZeroEventListener() });
                }
            });

【讨论】:

  • 提示:“Pre”事件监听器官方并不意味着修改实体。请改用 DefaultSaveEventListener。我知道互联网上到处都是修改实体的“Pre”监听器示例,但 Hibernate 开发人员回答说不支持这种用法,因此可能会产生新问题。
猜你喜欢
  • 1970-01-01
  • 2011-01-31
  • 1970-01-01
  • 2018-12-11
  • 2020-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多