Лучший способ удалить все строки в таблице с помощью NHibernate? - PullRequest
35 голосов
/ 29 января 2009

Для обеспечения независимости моих интеграционных тестов я удаляю все старые данные и вставляю новые тестовые данные перед каждым тестом. Есть ли лучший способ сделать это, чем просто запросить все объекты и удалить их один за другим?

Я рассмотрел написание хранимого процесса, который запускает "delete from tablename ;" для каждой таблицы, которая должна быть очищена. Это должно быть немного быстрее, но было бы неплохо сделать это без выполнения SQL-запросов или вызова SP через NH.

Я использую ванильный NHibernate и Linq для NHibernate. Я считаю, что у Castle Active Record есть что-то вроде Foo.DeleteAll (), но я не хочу использовать Active Record для этого проекта.

Есть идеи?

Спасибо / Эрик

UPDATE:

Поскольку этот вопрос был задан и получен ответ, команда NHibernate достигла прогресса. Как объясняет Айенде в этом сообщении в блоге , теперь вы можете напрямую выполнять запросы DML без необходимости извлечения каких-либо сущностей NHibernate.

Чтобы удалить все объекты Foo, вы можете сделать это так:

using (ISession session = ...)
using (ITransaction transaction = session.BeginTransaction())
{
    session.CreateQuery("delete Foo f").ExecuteUpdate();

    transaction.Commit();
}

Этот запрос будет генерировать следующий SQL:

delete from Foo

, что должно быть значительно быстрее, чем сначала извлекать сущности, а затем удалять их. Однако будьте осторожны, поскольку подобные запросы не влияют на кэш 1-го уровня.

Ответы [ 3 ]

32 голосов
/ 29 января 2009

В TearDown моих UnitTests я в основном делаю это:

using( ISession s = ... )
{
   s.Delete ("from Object o");
   s.Flush();
}

Это должно удалить все объекты. Если вы хотите удалить все экземпляры одного конкретного объекта, вы можете сделать это:

using( ISession s = .... )
{
    s.Delete ("from MyEntityName e");
    s.Flush();
}

Конечно, у этого метода есть недостаток, заключающийся в том, что NHibernate сначала извлечет сущности перед их удалением.

11 голосов
/ 31 мая 2013

Я использую атрибуты Fluent Nhibernate, поэтому я немного изменяю код, чтобы не создавать жесткие имена таблиц

private static void CleanUpTable<T>(ISessionFactory sessionFactory)
{
    var metadata = sessionFactory.GetClassMetadata(typeof(T)) as NHibernate.Persister.Entity.AbstractEntityPersister;
    string table = metadata.TableName;

    using (ISession session = sessionFactory.OpenSession())
    {
        using (var transaction = session.BeginTransaction())
        {
            string deleteAll = string.Format("DELETE FROM \"{0}\"", table);
            session.CreateSQLQuery(deleteAll).ExecuteUpdate();

            transaction.Commit();
        }
    }
}

использование

CleanUpTable<Person>(sessionFactory);
3 голосов
/ 01 ноября 2017

С NHibernate 5.0 теперь вы можете просто:

session.Query<Foo>().Delete();

Документация:

    //
    // Summary:
    //     Delete all entities selected by the specified query. The delete operation is
    //     performed in the database without reading the entities out of it.
    //
    // Parameters:
    //   source:
    //     The query matching the entities to delete.
    //
    // Type parameters:
    //   TSource:
    //     The type of the elements of source.
    //
    // Returns:
    //     The number of deleted entities.
    public static int Delete<TSource>(this IQueryable<TSource> source);
...