Лучший способ удалить все строки в таблице с помощью NHibernate?
Чтобы сохранить независимость моих интеграционных тестов, я удаляю все старые данные и вставляю новые тестовые данные перед каждым тестом. Есть ли лучший способ сделать это, чем просто запросить все объекты и удалить их один за другим?
Я рассмотрел написание хранимого процесса, который запускает "удалить из имени таблицы;" для каждой таблицы, которая должна быть очищена. Это должно быть немного быстрее, но было бы неплохо сделать это без выполнения SQL-запросов или вызова SP через NH.
Я использую ванильный NHibernate и Linq для NHibernate. Я считаю, что у Castle Active Record есть что-то вроде Foo.DeleteAll(), но я не хочу использовать Active Record для этого проекта.
Есть идеи?
Спасибо / Эрик
ОБНОВИТЬ:
Поскольку этот вопрос был задан и получен ответ, команда 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 ответа
В TearDown моих UnitTests я в основном делаю это:
using( ISession s = ... )
{
s.Delete ("from Object o");
s.Flush();
}
Это должно удалить все объекты. Если вы хотите удалить все экземпляры одного конкретного объекта, вы можете сделать это:
using( ISession s = .... )
{
s.Delete ("from MyEntityName e");
s.Flush();
}
Конечно, у этого метода есть недостаток, заключающийся в том, что NHibernate сначала извлечет сущности перед их удалением.
Я использую атрибуты 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);
С 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);