2012-03-13 66 views
1

我發現了一個的tuplizer的這個例子中節省空當的關係做保存0。由於我正在處理遺留數據庫模式上的應用程序,因此這是必需的。NHibernate的,保存爲0(零)DB空的參考價值

我想這裏的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(被描述爲骯髒的黑客3,閱讀從數據庫對象時使用),我得到這部分nullref例外,如果(typeof運算(IEntity),讀一本不相關的對象(而不是樣本)

我的映射如下(簡化):

Table("ej_sample"); 
     Not.LazyLoad(); 
     Id(s => s.Id, "sampleID").GeneratedBy.Native(); 
     References<Sample>(s => s.ParentSample, "parentSampleID").NotFound.Ignore(); 

當該對象不存在的parentSampleID列必須是0

我想,我只需要做上插入和更新髒黑客。 (可能在我的情況下只能插入)

On inser t,我想創建一個僞代理,但[2]中的代碼從db加載實體(可能使用空對象?!)。

插入骯髒的黑客:

 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例外:

 private readonly ISessionFactoryImplementor _sessionFactory; 

    public NullableTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) 
     : base(entityMetamodel, mappedEntity) { 
      _sessionFactory = entityMetamodel.SessionFactory; 

    } 

任何想法如何做到這一點?

+0

您將與ISessionImplementor無關的'ISession'強制轉換爲'ISessionImplementor'。更安全的是'session.GetSessionImplementor()' – Firo 2012-03-13 16:04:48

回答

1

簡單的解決方法是添加以下preinsert和更新前的監聽器。

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();

在你的SessionFactory,添加監聽兩個preinsert和更新前的事件(這裏先出):

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

提示:「Pre」事件監聽器正式不是用來修改實體的。改用DefaultSaveEventListener。我知道互聯網上充斥着修改實體的「Pre」偵聽器示例,但Hibernate開發人員回答說這種用法不受支持,因此可能會產生新問題。 – JustAMartin 2012-09-28 14:44:19