Сохранение нового объекта в прослушивателе событий PreInsert / PreDelete не сохраняется в базе данных - PullRequest
6 голосов
/ 13 апреля 2011

Я настроил прослушиватель событий PreInsert и PreDelete в NHibernate 2.1. Для вставок и удалений в конкретной таблице я хочу записать событие аудита в отдельную таблицу аудита.

public class AuditEventListener : IPreInsertEventListener, IPreDeleteEventListener 
{
    private static readonly ILog Log = LogManager.GetLogger(typeof(AuditEventListener));

    public bool OnPreInsert(PreInsertEvent @event)
    {
        if (!(@event.Entity is IAuditable))
            return false;

        return AuditEvent(@event.Session.GetSession(EntityMode.Poco),
            true, (@event.Entity as IAuditable));
    }

    public bool OnPreDelete(PreDeleteEvent @event)
    {
        if (!(@event.Entity is IAuditable))
            return false;

        return AuditEvent(@event.Session.GetSession(EntityMode.Poco),
            false, (@event.Entity as IAuditable));
    }

    private bool AuditEvent(ISession session, bool isInsert, IAuditable entity)
    {
        if (entity is ArticleBinding)
        {
            if (Log.IsDebugEnabled)
                Log.DebugFormat(" audit event ({0}), entity is ArticleBinding", ((isInsert) ? "Insert" : "Delete"));

            AddArticleBindingAuditEvent(session, isInsert, 
                (entity as ArticleTagBinding));

        }
        return false;
    }

    private void AddArticleBindingAuditEvent(ISession session, 
        bool isInsert, ArticleBinding binding)
    {
        var auditRecord = new AuditArticleBinding()
                              {
                                  ArticleId = binding.ArticleId,
                                  Action = (isInsert) ? "Add" : "Delete",
                                  LoggedBy =                                          string.IsNullOrEmpty(Thread.CurrentPrincipal.Identity.Name)
                                          ? "Unknown"
                                          : Thread.CurrentPrincipal.Identity.Name
                              };

        session.Save(auditRecord);
    }
}

Я работал над проблемой использования того же сеанса, который вызывал исключение. Теперь весь код работает нормально, и мои операторы журнала сбиты, но запись аудита никогда не вставляется. Используя NHProf, я вижу, что вызов INSERT никогда не происходит.

Почему приведенный выше код не вызывает вставку?

Ответы [ 2 ]

4 голосов
/ 20 июля 2011

Я сейчас работаю над точно такой же вещью и столкнулся с той же проблемой.Попытка сохранить новый объект и оператор INSERT даже не выполняется.Я нашел статью о с использованием прослушивателей Pre [Update | Insert] для аудита каждой записи , где один комментарий спрашивает о вставке новой сущности, а автор отвечает, что требуется дочерний сеанс.

private void AddArticleBindingAuditEvent(ISession session, 
    bool isInsert, ArticleBinding binding)
{
    var childSession = e.Session.GetSession(EntityMode.Poco);
    var auditRecord = new AuditArticleBinding()
                          {
                              ArticleId = binding.ArticleId,
                              Action = (isInsert) ? "Add" : "Delete",
                              LoggedBy = string.IsNullOrEmpty(Thread.CurrentPrincipal.Identity.Name)
                                      ? "Unknown"
                                      : Thread.CurrentPrincipal.Identity.Name
                          };

    childSession.Save(auditRecord);
    childSession.Flush();
}

Еще один справочник для вас (который я нашел сегодня) - Аудит с помощью NHibernate Listeners .В нем приведен полный пример вставки нового журнала аудита, но используются прослушиватели Post и он не привязан к сущности (выполняет почти то же самое, что и я, с сохранением для поиска измененных значений).Я не уверен, в чем выгода от использования прослушивателей Pre.

И, как «просто на всякий случай», вы должны убедиться, что вы подключили прослушиватель событий к вашей конфигурации:

var eventListener = new AuditEventListener();
config.SetListener(ListenerType.PreInsert, eventListener);
config.SetListener(ListenerType.PreDelete, eventListener);

Полное раскрытие информации : Я довольно новичок в NHibernate, поэтому, если я что-то пропустил или мог бы сделать лучше, пожалуйста, дайте мне знать.Описанный выше метод работает для меня в том, что моя запись успешно вставлена ​​в базу данных, но в некоторых случаях она не работает.Хотя я почти уверен, что это специфично для моего приложения (из которого я новичок в кодовой базе, так что все еще работаю)

0 голосов
/ 12 августа 2011

Потратив целый день на попытки выяснить первопричину проблемы, я надеюсь, нашел этот поток , который объясняет:

Глядя на код Hibernate, онПохоже, что вставляется только с использованием атрибута «состояние» PreInsertEvent.Поэтому, даже если вы обновляете event.getEntity (), я не думаю, что он вставляется во время фазы вставки.

Решение состоит в 1) обновлении сущности для прохождения проверки (например, @NotNull).) и 2) обновление состояния, чтобы новые значения сохранялись в базе данных!

В моем приложении это приводит к уродливому коду:

@Override
public boolean onPreInsert(PreInsertEvent event) {
    Object entity = event.getEntity();
    // Assumption: entity cannot be null

    if (entity instanceof AbstractBase) {
        String[] names = event.getPersister().getPropertyNames();
            for (int i = 0; i < names.length; ++i) {
                if ("insertWhen".equals(names[i])) {
                ((AbstractBase<?>) entity).setInsertWhen(new Date());
                    event.getState()[i] = ((AbstractBase<?>) entity).getInsertWhen();
                }
            else if (...) {
            ...
        }
    }
}

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

Надеюсь, это поможет.

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