2009-04-23 5 views
20

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

  1. Fetch список объектов (назовем их список пользователей, List<User>) из базы данных
  2. Изменить свойства этих объектов, (Users.Foreach(User=>User.Country="Antartica")
  3. Update каждый элемент обратно индивидуально (Users.Foreach(User=>NHibernate.Session.Update(User)).
  4. Звоните Session.Flush, чтобы обновить базу данных.

Это хороший подход? Это приведет к большому количеству рейсов между моим кодом и базой данных?

Как вы думаете? Или есть более элегантное решение?

+0

3: Я думаю, что вы не имеете в виду совершить, вы имеете в виду обновление. –

+0

Да, вы правы; Я имел в виду обновление. – Graviton

+3

Вы должны удалить Шаг 3, потому что 'Session.Update' не« обновляет каждый элемент назад ». Вместо этого NHibernate наблюдает за всеми изменениями, внесенными в объекты, и самостоятельно записывает изменения в базу данных, без вашего ведома. – yfeldblum

ответ

20

Начиная NHibernate 3.2 пакетных заданий имеют улучшение, которые сводят к минимуму базы данных круглые поездки. Более подробную информацию можно найти на сайте HunabKu blog. Вот пример из него - эти пакетные обновления делать только 6: туда и обратно

using (ISession s = OpenSession()) 
using (s.BeginTransaction()) 
{ 
    for (int i = 0; i < 12; i++) 
    { 
     var user = new User {UserName = "user-" + i}; 
     var group = new Group {Name = "group-" + i}; 
     s.Save(user); 
     s.Save(group); 
     user.AddMembership(group); 
    } 
    s.Transaction.Commit(); 
} 
4

Вам не нужно обновлять, ни на одном уровне:

IList<User> users = session.CreateQuery (...).List<User>; 
users.Foreach(u=>u.Country="Antartica") 
session.Transaction.Commit(); 

Я думаю, NHibernate пишет партию для всех изменений.

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

+1

Это зависит от FlushMode. session.FlushMode = FlushMode.Никогда не будет сохранен без явного вызова Flush(). Ваш код будет работать с FlushMode.Commit, но – MPritchard

+0

@Stefan Я не могу получить пакетные обновления для работы ... можете ли вы помочь http://stackoverflow.com/questions/26471952/nhibernate-executing-updates-in-batches – harishr

8

Вы можете установить размер партии для обновлений в конфигурационном файле nhibernate.

<property name="hibernate.adonet.batch_size">16</property> 

И вам не нужно вызывать Session.update (User) там - только на одном уровне или совершить сделку и NHibernate будет обрабатывать вещи для вас.

EDIT: Я собирался разместить ссылку на соответствующий раздел в NHibernate документации, но сайт вниз - here's an old post from Ayende по теме:

Что касается того, здесь является использование NHibernate (или любой ORM) хороший подход, это зависит от контекста. Если вы делаете одноразовое обновление каждой строки в большой таблице с одним значением (например, установите всех пользователей в страну «Антарктида» (которая является континентом, а не страной, кстати!), То вам, вероятно, следует используйте инструкцию sql UPDATE. Если вы собираетесь обновлять сразу несколько записей в стране как часть своей бизнес-логики при общем использовании вашего приложения, то использование ORM может быть более разумным методом. Это зависит от количества из строк, которые вы обновляете каждый раз.

Возможно, самый разумный вариант здесь, если вы не уверены в том, чтобы настроить параметр batch_size в NHibernate и посмотреть, как это работает. Если производительность системы неприемлема, посмотрите на реализацию прямого кода sql UPDATE в вашем коде.

2

Нет, это не очень хороший подход!

Native SQL во много раз лучше для такого рода обновлений.

UPDATE USERS SET COUNTRY = 'Antartica'; 

Просто не может быть проще, и механизм базы данных будет обрабатывать эту сто раз более эффективно, чем строки в то время, когда код Java.

+1

Он использует NHibernate, это .NET not Java :) –

+1

Я запутался здесь: если ваш аргумент верен, тогда не должно быть никакого использования ORM, потому что db-движок всегда будет обрабатывать SQL-код во много раз более эффективно, чем ORM-код ... am Я прав? – Graviton

+0

Ngu, я обновил свой ответ, чтобы ответить на ваш комментарий. –

39

Я знаю, что я опоздал на вечеринку на это, но думал, что вы можете, как знать, что это теперь возможно с помощью HQL в NHibernate 2.1+

session.CreateQuery(@"update Users set Country = 'Antarctica'") 
.ExecuteUpdate(); 
+0

Порекомендовал бы ответ marisks для тех, кто использует NH 3.2+ – MPritchard

+1

Это работает только в том случае, если свойство для всех 'Users' будет установлено на то же значение' Antartica'. Но если 'List ' пакет обновлен со всеми разными округами, этот 'HQL' не будет работать. Хотя это решение конкретной примерной ситуации ОП. –

1

Начиная с NHibernate 5.0 можно сделать массовые операции с использованием LINQ.

session.Query<Cat>() 
.Where(c => c.BodyWeight > 20) 
.Update(c => new { BodyWeight = c.BodyWeight/2 }); 

См Updating entities

Смежные вопросы