Для выполнения bulk операций над базой данных в NHibernate есть специальная StatelessSession. Интерфейс данного объекта отличается от стандартного Session, у него нет методов Save, SaveOrUpdate и т.д., зато есть Insert, Update, Delete.
Особенность StatelessSession в том, что она не следит за сохранёнными объектами, значит это следующее, рассмотрим следующий пример кода:
using(var transaction = Session.BeginTransaction()) { var someObject = Session.Get<SomeObject>(id); someObject.SomeProperty = "some new value"; transaction.Commit(); }
В результате выполнения этого кода someObject будет обновлен не только в вашем приложении, но в и базе данных.
За подобное приходится платить производительностью, в частности именно это стало причиной того, что на OrmBattle Nhibernate получает далеко не самые лучшие отметки (кстати по этому поводу есть довольно хороший ответ от Ayende).
А теперь перейдем к основной теме. Показать хотелось бы следующее:
ISessionFactory sessionFactory = Fluently.Configure() .Database(MsSqlConfiguration.MsSql2008.ConnectionString("connString") .AdoNetBatchSize(40)) // important! .Mappings(x=>x.FluentMappings.AddFromAssemblyOf<TestHilo>()) .BuildSessionFactory(); IStatelessSession session = sessionFactory.OpenStatelessSession(); for (int i = 0; i < 60; i++) { var testHilo = new TestHilo { Field1 = "field" + i, Field2 = i }; session.Insert(testHilo); } session.Dispose();
Данный код должен вставить 60 записей в базу. На самом же деле вставится только 40. Происходит это из-за установленного AdoNetBatchSize (подробнее об этом в предыдущем посте). Когда это обнаружилось первое что захотелось сделать это вызвать session.Flush(). Но у StatelessSession нет такого метода :).
В общем решением будет следующее – выполнять данный цикл в рамках одной транзацкии:
using (ITransaction transaction = session.BeginTransaction()) { for (int i = 0; i < 60; i++) { var testHilo = new TestHilo { Field1 = "field" + i, Field2 = i }; session.Insert(testHilo); } transaction.Commit(); }
Такой код вставит все 60 записей.