2012-03-13 2 views
1

Я нашел этот пример tuplizer, чтобы сделать сохранения 0 при сохранении нулевых отношений. Это необходимо, так как я работаю над приложением по схеме устаревшей базы данных.NHibernate, сохранить нулевое эталонное значение в БД, как 0 (ноль)

Я попытался tuplizer здесь: http://nhforge.org/blogs/nhibernate/archive/2011/01/28/how-to-use-0-instead-of-null-for-foreign-keys.aspx

В этом примере я получил NullReferenceException для ProxyFactory. Затем я нашел обновление для кода здесь: 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, если нет такого объекта не существует

Я понял, я должен только сделать ухищрений на вставке и обновлении. (возможно, в моем случае только вставка).

На вставке t, я хочу создать поддельный прокси, но код в [2] загружает объект из db (возможно, для использования объекта 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; 
    } 

Тогда я получаю nullref исключение на _sessionfactory, который устанавливается в CTOR :

 private readonly ISessionFactoryImplementor _sessionFactory; 

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

    } 

Любые идеи, как это осуществить?

+0

вы передали несвязанный 'ISession'' 'ISessionImplementor'. Более безопасным является 'session.GetSessionImplementor()' – Firo

ответ

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 идентификаторов, например: References<User>(s => s.User, "userID").NotFound.Ignore().LazyLoad();

В вашем SessionFactory добавить слушатель для обоих preinsert и preupdate событий (первый показанные здесь):

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

Совет: прослушиватели событий «Pre» официально не предназначены для изменения объектов. Вместо этого используйте DefaultSaveEventListener. Я знаю, что в Интернете полно примеров слушателей «Pre», которые изменяют сущности, но разработчики Hibernate ответили, что такое использование не поддерживается, поэтому оно может создавать новые проблемы. – JustAMartin

 Смежные вопросы

  • Нет связанных вопросов^_^