Детская сессия NHibernate не очищается должным образом - PullRequest
3 голосов
/ 21 июля 2010

Мы внедрили систему аудита через прослушиватели событий NHibernate. В нашем слушателе мы отслеживаем все изменения и записываем их в наши таблицы аудита. Чтобы попытаться максимизировать производительность, мы использовали Guid для наших таблиц аудита, чтобы мы могли как можно больше пакетировать наши обновления.

Мы записываем обновления для «дочернего сеанса», которые мы получаем следующим образом:

 protected ISession GetSession(AbstractEvent @event)
 {
     if (@event == null)
     {
        throw new ArgumentNullException("event");
     }

        ISession childSession = @event.Session.GetSession(EntityMode.Poco);

        return childSession;
 } 

Из документации NHibernate этот сеанс должен быть "дочерним" сеансом, который наследует все атрибуты своего родителя, включая транзакцию.

Как только мы создали объект, мы сохраняем его в сеансе с:

childSession.Save(auditLogEntry);

Все это вызывается внутри транзакции, и я ожидаю, что изменения, сделанные в childSession, сбрасываются после фиксации транзакции. К сожалению, ничего не происходит и изменения не сбрасываются.

Следует отметить, что я могу заставить это работать с ручным сбросом сразу после сохранения, но это не будет работать для нас, потому что изменения больше не будут пакетироваться (что приведет к неприемлемой производительности).

Сначала я думал, что это поведение ограничено событиями, но я смог абстрагировать его в модульный тест для дублирования поведения.

  public void When_Saving_Audit_Log_Records_To_Child_Session_Flushes_When_Transaction_Committed()
    {
        ISession session = GetSession();
        session.FlushMode = FlushMode.Commit;

        ITransaction transaction = session.BeginTransaction();

        ISession childSession = session.GetSession(EntityMode.Poco);

        AuditLogEntry entry = CreateAuditLogEntry();
        entry.AddAuditLogEntryDetail(CreateAuditLogEntryDetail());
        entry.AddAuditLogEntryDetail(CreateAuditLogEntryDetail());

        childSession.Save(entry);
        transaction.Commit();
    }

protected ISession GetSession()
    {
        return _sessionFactory.OpenSession();
    }

Я знаю, что это не ваш обычный вопрос о NHibernate, но если у кого-то есть какой-либо опыт или совет, которым я могу поделиться, я бы с удовольствием его услышал.

У меня есть 2 секунды до того, как я просто записываю записи аудита в очередь, но я хотел исчерпать все возможности, прежде чем сдаться.

Заранее спасибо,

Steve

Ответы [ 2 ]

0 голосов
/ 06 марта 2017

Мы выполняем аудит таким же образом (с GUID PK).При использовании генератора Identity PK каждый вызов Save немедленно выдавал INSERT, но при использовании GUID INSERT выполняются только во время сброса.Мы решили это несколько лет назад, исправив источник NHibernate.В SessionImpl.cs в методе Flush (около строки 1467) я добавил следующее:

// Flush children when parent is flushed.
if (childSessionsByEntityMode != null) {
    foreach (var childSession in childSessionsByEntityMode) {
        childSession.Value.Flush();
    }
}
0 голосов
/ 14 сентября 2013

Проблема из FlushMode.Commit: в этом режиме NHibernate будет сбрасывать сеанс только один раз при совершении транзакции.Поэтому после сброса он не будет сбрасываться в другой раз, и любые изменения после сброса НЕ будут сбрасываться.

Чтобы решить эту проблему, вы можете либо сбросить сеанс вручную, либо перейти на FlushMode.Auto.Однако, если вы используете Auto, остерегайтесь StackOverflowException с прослушивателями событий и / или перехватчиками, потому что с Auto NHibernate будет сбрасываться перед запросом, вызывая OnFlushDirty в результате, поэтому, если вы запросите что-то в OnFlushDirty, это вызоветдругой сброс, который затем вызывает OnFlushDirty снова в бесконечном цикле.Чтобы предотвратить эту ситуацию, вы должны либо временно изменить FlushMode на Never, либо внедрить систему, чтобы определить, какие изменения были обработаны, чтобы избежать повторной обработки одного и того же изменения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...