NHibernate ISession.Save () - Почему мои сущности сохраняются немедленно?

Я создаю большое количество сущностей с помощью NHibernate, присоединяю их к моему ISession, а затем использую транзакцию для фиксации моих изменений в базе данных. Пример кода ниже:

ISession _context = SessionProvider.OpenSession();

//Create new entities
for(int i=0; i<100; i++)
{
    MyEntity entity = new MyEntity(i);

    //Attach new entity to the context
    _context.Save(entity);
}

//Persist all changes to the database
using(var tx = _context.BeginTransaction())
{
    //Flush the session
    tx.Commit();
}

У меня создалось впечатление, что строка _context.Save () просто информирует ISession о новом объекте, но никакие изменения в базе данных не сохраняются, пока я не очищу сеанс через строку tx.Commit ().

Однако я заметил, что база данных получает новую сущность каждый раз, когда я вызываю _context.Save (). В результате я получаю слишком много индивидуальных обращений к базе данных.

Кто-нибудь знает, почему ISession.Save () автоматически сохраняет изменения? Я что-то неправильно понял о том, как ведет себя NHibernate? Спасибо.

*** РЕДАКТИРОВАТЬ - Просто чтобы прояснить (в свете двух предложенных ответов) - моя проблема в том, что база данных обновляется, как только я вызываю _context.Save (). Я не жду этого. Я ожидаю, что в базу данных ничего не будет вставлено, пока я не вызову tx.Commit (). К сожалению, ни один из двух предложенных ответов пока не помогает.

Некоторую полезную информацию о генераторах идентичности можно найти здесь


person JMc    schedule 26.06.2011    source источник
comment
Это ожидаемое поведение, Save выполняется за пределами Transaction. Правильный ответ должен быть @StuffHappens внизу.   -  person THBBFT    schedule 12.06.2016
comment
@THBBFT, нахождение вне транзакции не приводит к отправке сохранения в базу данных. StuffHappens дает неверный ответ, почему он вставляется при вызове Save. Этот ответ просто гарантирует, что вставки будут откатаны, но это не было проблемой OP. И его редакция еще раз подтверждает это.   -  person Frédéric    schedule 18.06.2017


Ответы (6)


Какой генератор идентичности вы используете? Если вы используете генераторы пост-вставки, такие как MSSQL / MySQL Identity или Oracle sequence, для генерации значения ваших полей Id, это ваша проблема.

Из раскрыты генераторы POID NHibernate:

Генераторы вставки постов, как следует из названия, присваивают идентификатор после того, как объект сохраняется в базе данных. Оператор выбора выполняется для базы данных. У них много недостатков, и, на мой взгляд, их нужно использовать только на заброшенных проектах. Именно эти генераторы МЫ НЕ ПРЕДЛАГАЕМ как команда NH.

К недостаткам можно отнести следующие

  1. Использование этих стратегий нарушает работу Unit Of Work. Неважно, используете ли вы FlushMode.Commit, каждое сохранение приводит к оператору вставки в базу данных. Лучше всего отложить вставки до коммита, но при использовании генератора пост-вставок он фиксируется при сохранении (чего не делает UoW).
  2. Эти стратегии аннулируют дозатор, вы не можете воспользоваться возможностью отправки нескольких запросов одновременно (так как он должен перейти в базу данных во время сохранения)
person rebelliard    schedule 26.06.2011
comment
Я думаю, что это может быть проблема на самом деле. В настоящее время в моих файлах конфигурации установлено: ‹generator class = identity /›. Я протестирую сегодня вечером и помечу как ответ, если это проблема. Спасибо! - person JMc; 27.06.2011
comment
Я использовал личность в качестве генератора идентификаторов, что, кажется, является причиной моей проблемы. Сейчас я ищу подходящие альтернативы для шаблона «Единица работы / Репозиторий», где я хочу явно очистить сеанс самостоятельно после связывания многих сущностей с ISession. Спасибо. - person JMc; 05.07.2011

Пытаться:

using(Session _context = SessionProvider.OpenSession())
using(var tx = _context.BeginTransaction())
{
    //Create new entities
    for(int i=0; i<100; i++)
    {
        MyEntity entity = new MyEntity(i);

        //Attach new entity to the context
        _context.Save(entity);
    }

    //Flush the session
    tx.Commit();
}
person StuffHappens    schedule 26.06.2011
comment
Пытаюсь добраться до вершины. - person THBBFT; 12.06.2016

Вы можете установить размер партии в своей конфигурации:

<add key="hibernate.batch_size" value="10" /> 

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

person Peter    schedule 26.06.2011

Попробуйте установить для FlushMode значение Commit:

ISession _context = SessionProvider.OpenSession();
context.FlushMode = FlushMode.Commit;

Предложение коллег по установке размера партии тоже хорошо.

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

person Jamie Ide    schedule 26.06.2011

Что ж

  1. Ответ мятежника - это возможность, зависящая от вашего картографирования
  2. вы не используете явные транзакции (ответ StuffHappens)
  3. режим промывки по умолчанию автоматический, и это усложняет ситуацию (ответ Джейми Айдэ)
  4. если каким-либо изменением вы выполняете какие-либо запросы с использованием nhibernate api, поведение по умолчанию заключается в том, чтобы сначала очистить кеш в базе данных, чтобы результаты этих запросов соответствовали представлению сущности сеанса.
person Jaguar    schedule 27.06.2011

Как насчет :

ISession _context = SessionProvider.OpenSession();

//Persist all changes to the database
using(var tx = _context.BeginTransaction())
{
    //Create new entities
    for(int i=0; i<100; i++)
    {
        MyEntity entity = new MyEntity(i);

        //Attach new entity to the context
        _context.Save(entity);
    }

    //Flush the session
    tx.Commit();

}
person Tristan    schedule 26.06.2011