NHibernate ISession.Save() - Почему это сохраняет мои сущности сразу?
Я создаю большое количество сущностей с помощью NHibernate, присоединяю их к моей сессии и затем использую транзакцию для фиксации моих изменений в базе данных. Пример кода ниже:
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(). К сожалению, ни один из двух предложенных ответов пока не помогает в этом.
Некоторая хорошая информация о генераторах идентичности может быть найдена здесь
6 ответов
Какой генератор идентичности вы используете? Если вы используете генераторы после вставки, такие как MSSQL/MySQL Identity
или Oracle sequence
чтобы создать значение ваших полей Id, это ваша проблема.
Из NHibernate выявлены POID генераторы:
Генераторы пост-вставок, как следует из названия, присваивают идентификаторы после сохранения сущности в базе данных. Оператор выбора выполняется для базы данных. У них много недостатков, и, по моему мнению, они должны использоваться только в проектах на коричневых полях. Эти генераторы - это то, что МЫ НЕ ПРЕДЛАГАЕМ, как NH Team.
Некоторые из недостатков следующие
- Единица работы нарушается с использованием этих стратегий. Не имеет значения, используете ли вы FlushMode.Commit, каждое сохранение приводит к оператору вставки в БД. Рекомендуется отложить вставки до коммита, но использование генератора пост-вставок делает его фиксацией при сохранении (что UoW не делает).
- Эти стратегии сводят на нет дозатор, вы не можете использовать преимущество отправки нескольких запросов одновременно (так как он должен идти в базу данных во время сохранения)
Пытаться:
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();
}
Вы можете установить размер партии в вашей конфигурации:
<add key="hibernate.batch_size" value="10" />
Или вы можете установить его в коде. И убедитесь, что вы делаете свои сохранения в рамках транзакции.
Попробуйте установить FlushMode для коммита:
ISession _context = SessionProvider.OpenSession();
context.FlushMode = FlushMode.Commit;
Предложение пэра установить размер партии также хорошо.
Насколько я понимаю, при использовании столбцов идентификаторов базы данных NHibernate будет откладывать вставки до тех пор, пока сеанс не будет сброшен, если только ему не нужно выполнить вставку, чтобы получить внешний ключ или убедиться, что запрос возвращает ожидаемые результаты.
Что ж
- Ответ мятежника возможен в зависимости от вашего отображения
- вы не используете явные транзакции (ответ StuffHappens)
- режим сброса по умолчанию - автоматический, что усложняет ситуацию (ответ Джейми Иде)
- если при каких-либо изменениях вы выполняете какие-либо запросы с использованием API-интерфейса nhibernate, то поведение по умолчанию - сначала сбросить кэш в базу данных, чтобы результаты этих запросов соответствовали представлению сущности сеанса.
Как насчет:
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();
}