NHibernate: Как удалить набор объектов? - PullRequest
2 голосов
/ 27 декабря 2011

Допустим, у нас есть 100 объектов типа User, и у каждого пользователя есть однозначная ссылка.Размер пакета в конфигурации NHibernate установлен на 50. Таким образом, если мы удалим все 100 объектов, NHibernate запустит 200 подключений к БД.Я хочу удалить их с 4 соединениями с 50 запросами в каждом соединении.Приведенный ниже код является копией / вставкой из моих методов пакетной вставки, которая работает, как и ожидалось:

public void BatchDelete(IEnumerable<T> entitiesToDelete)
    {
        int batchSzie = Session.GetSessionImplementation().Batcher.BatchSize;
        int batchedInsertsCount = 0;
        foreach (var entity in entitiesToDelete)
        {
            batchedInsertsCount++;
            Session.Delete(entity);
            if (batchedInsertsCount % batchSzie == 0)
            {
                Session.Flush();
                Session.Clear();
            }
        }
    }

РЕДАКТИРОВАТЬ: я забыл упомянуть, что я нахожусь в транзакции.

Ответы [ 3 ]

4 голосов
/ 27 декабря 2011
            Session.Flush();
            Session.Clear();

Обычно указывает, что вы делаете что-то не так, начинайте добавлять транзакции и удаляйте:

if (batchedInsertsCount % batchSzie == 0)

Другим подходом может быть запрос с удалением и в:

            // fill batch with id list of items you want to delete
            _session.CreateQuery(String.Format("DELETE  FROM TABLENAME WHERE Id IN (:idsList)", _domainObject.Name))
                    .SetParameterList("idsList", batch.ToArray())
                    .ExecuteUpdate();

Убедитесь, что вы проверили максимальные идентификаторы 2100, то есть максимальные параметры, которые вы можете задать для sqlserver.

3 голосов
/ 27 декабря 2011

Вы слишком усложняете это.

Просто настройте желаемый размер пакета, сделайте все необходимые Session.Delete вызовы и затем подтвердите вашу транзакцию.

NHibernate выполнит entitiesToDelete.Count() / batch size запросов.

Вот пример кода:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    foreach (var foo in session.Query<Foo>())
        session.Delete(foo);
    tx.Commit();
}

И пример конфигурации:

var config = new Configuration();
config.SessionFactory()
      .Integrate.Using<MsSql2008Dialect>().Connected.Using("...")
      .BatchingQueries.Each(10);

(Я устанавливаю явное значение для размера пакета, но NH 3,2по умолчанию 20 IIRC)

Если имеются каскадные коллекции, необходимо убедиться, что удаления обрабатываются БД.

Вам необходимо определить FK как ON DELETE CASCADE и разрешить NHзнать об этом:

<class name="Foo">
  <id ...>...</id>
  <bag name="Bars" inverse="true" cascade="all">
    <key column="FooId" on-delete="cascade" />
    <one-to-many class="Bar" />
  </bag>
</class>
<class name="Bar">
  <id ...>...</id>
  <many-to-one name="Foo" column="FooId" />
</class>

В этом случае Foo имеет коллекцию Bars, сохраненную в столбце FooId.

0 голосов
/ 27 декабря 2011

Прежде всего вы не устанавливаете размер пакета для сеанса (session.BatchSize ()), поэтому он будет использовать то, что всегда является значением по умолчанию или то, что вы настроили при создании sessionfactory. Но что более важно, нет поддержки пакетного удаления. Даже если вы правильно установите session.BatchSize (), это не даст никакого эффекта (по крайней мере, для NHibernate 3.2 и SQL Server 2008). У Айенде есть запись в блоге, в которой показано, как решить проблему .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...