Перехват операций персистентности NHibernate над свойствами ICollection (многие ассоциации) - PullRequest
1 голос
/ 08 февраля 2012

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

Как это сделать?

Эти свойства коллекции обычно сопоставляются с ассоциациями «один ко многим» или «многие ко многим».Итак, когда у нас есть что-то вроде этого:

myEntity.List.Add(new Item());
myEntity.List.Add(new Item());
...
session.Save(myEntity);

Для отображения, имеющего два класса (сущности) и однонаправленную ассоциацию «многие ко многим», я хотел бы иметь только два выражения sql: INSERT INTO и PROCEDURE CALL, который ожидает получить список значений, разделенных запятыми, который является ключом значений из коллекции List выше.Коллекция ключей может быть сохранена только в этой системе, вызывая процедуру со списком значений (csv).

Такую настройку можно выполнить?

Ответы [ 2 ]

1 голос
/ 14 февраля 2012

Ну, я принял решение, реализующее NHibernate Listeners, поэтому у меня есть такой слушатель:

public class CustomSaveUpdateEventListener : IPostInsertEventListener, IPostUpdateEventListener {

    private void ScheduleToCommit(AbstractPostDatabaseOperationEvent @event) {
        // Some filter
        if (@event.Entity.GetType().FullName.Equals(MY_ENTITY_TO_INTERCEPTS) {
            object o = @event.Entity;

            // Some logic...
            // ...
            // ...

            IQuery namedQuery = @event.Session.GetNamedSQLQuery(MY_NAMED_QUERY);
            //namedQuery.SetParameter(...); // <== You can set parameters
            //namedQuery.ExecuteUpdate(); // <== DO NOT EXCEUTE HERE, this launches more events recursively and can generate stackoverflow

            @event.Session.ActionQueue.RegisterProcess(new MyActionBeforeCommit(@event, namedQuery).SaveValuesOperation);
            }
        }
    }

    public void OnPostInsert(PostInsertEvent @event) {
        ScheduleToCommit(@event);
    }


    public void OnPostUpdate(PostUpdateEvent @event) {
        ScheduleToCommit(@event);
    }
}

И мой объект MyActionBeforeCommit() планируется запустить только тогда, когда и если транзакция совершается. Итак, в моем «будущем действии» я имею:

public class MyActionBeforeCommit {
    private AbstractPostDatabaseOperationEvent e;

    private IQuery query;

    public MyActionBeforeCommit(AbstractPostDatabaseOperationEvent e, IQuery query) {
        this.e = e;
        this.query = query;
    }

    public void SaveValuesOperation() {
        // Here your query will be executed only when a transation is commited, if 
        // it's rolledback this won't be executed
        query.ExecuteUpdate(); 
    }
}

И, наконец, нам нужно зарегистрировать нового слушателя в конфигурации NHibernate, например:

Configuration.SetListener(ListenerType.PostInsert, new    CustomSaveUpdateEventListener());
Configuration.SetListener(ListenerType.PostUpdate, new CustomSaveUpdateEventListener());

И это работает очень хорошо. Это очень хорошая функция NHibernate, очень мощная.

0 голосов
/ 08 февраля 2012

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

Похоже, вам нужно написать собственный NHibernate "Диалект". Вот некоторые рекомендации здесь и здесь, как это сделать.

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

Переопределение диалектов полностью поддерживается NHibernate. Если это не работает для вас, возможно, вам даже придется взглянуть на пользовательский AbstractEntityPersister, но я не знаю, как это сделать с записями в файле конфигурации.

Вы можете найти источники NHibernate 3.2 здесь .

Совершенно другой подход может заключаться в использовании стандартного постоянства NHibernate для локальной базы данных, например sql-server CE и выполните скрипт синхронизации для «реального» постоянства.

...