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