为了保持我的集成测试独立,我删除所有旧数据并在每次测试之前插入新的测试数据。有没有比仅仅查询所有实体并逐个删除它们更好的方法呢?
我考虑过编写一个运行“从 tablename 删除”的存储过程;对于要清除的每个表。这应该快得多,但如果不进行SQL查询或通过NH调用SP,这样做会很好。
我正在使用vanilla NHibernate和Linq来NHibernate。我相信Castle Active Record有类似Foo.DeleteAll()的东西,但我不想在这个项目中使用Active Record。
有什么想法吗?
谢谢/ Erik
更新
自从提出并回答了这个问题以来,NHibernate团队取得了进展。正如Ayende在this blog post中解释的那样,您现在可以直接执行DML查询,而NHibernate不必获取任何实体。
要删除所有Foo对象,您可以这样做:
using (ISession session = ...)
using (ITransaction transaction = session.BeginTransaction())
{
session.CreateQuery("delete Foo f").ExecuteUpdate();
transaction.Commit();
}
此查询将生成以下SQL:
delete from Foo
要比首先获取实体然后删除实体要快得多。但要小心,因为像这样的查询不会影响1级缓存。
答案 0 :(得分:32)
在我的UnitTests的TearDown中,我主要是这样做的:
using( ISession s = ... )
{
s.Delete ("from Object o");
s.Flush();
}
这应删除所有实体。 如果要删除一个特定实体的所有实例,可以执行以下操作:
using( ISession s = .... )
{
s.Delete ("from MyEntityName e");
s.Flush();
}
当然,这种方法存在一个缺点,那就是NHibernate会在删除实体之前首先获取实体。
答案 1 :(得分:11)
我使用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);
答案 2 :(得分:3)
使用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);