我可以刷新我的NHibernate会话并在不提交事务的情况下获得新会话吗?
我正在使用Castle ActiveRecord进行持久性测试,我正在尝试为我的持久性测试编写一个基类,它将执行以下操作:我可以刷新我的NHibernate会话并在不提交事务的情况下获得新会话吗?,nhibernate,testing,castle-activerecord,database-testing,Nhibernate,Testing,Castle Activerecord,Database Testing,我正在使用Castle ActiveRecord进行持久性测试,我正在尝试为我的持久性测试编写一个基类,它将执行以下操作: 为每个测试用例打开一个事务,并在测试用例结束时回滚它,这样我就可以为每个测试用例获得一个干净的DB,而不必为每个测试用例重建模式 提供了刷新我的NHiBalEnter会话并在测试中间获得一个新的会话的能力,这样我就知道我的持久操作真的命中了数据库而不是NHiBiess会话。 为了证明我的基类(ARTestBase)正在工作,我提出了以下示例测试 [TestFixture
- 为每个测试用例打开一个事务,并在测试用例结束时回滚它,这样我就可以为每个测试用例获得一个干净的DB,而不必为每个测试用例重建模式
- 提供了刷新我的NHiBalEnter会话并在测试中间获得一个新的会话的能力,这样我就知道我的持久操作真的命中了数据库而不是NHiBiess会话。
ARTestBase
)正在工作,我提出了以下示例测试
[TestFixture]
public class ARTestBaseTest : ARTestBase
{
[Test]
public void object_created_in_this_test_should_not_get_committed_to_db()
{
ActiveRecordMediator<Entity>.Save(new Entity {Name = "test"});
Assert.That(ActiveRecordMediator<Entity>.Count(), Is.EqualTo(1));
}
[Test]
public void object_created_in_previous_test_should_not_have_been_committed_to_db()
{
ActiveRecordMediator<Entity>.Save(new Entity {Name = "test"});
Assert.That(ActiveRecordMediator<Entity>.Count(), Is.EqualTo(1));
}
[Test]
public void calling_flush_should_make_nhibernate_retrieve_fresh_objects()
{
var savedEntity = new Entity {Name = "test"};
ActiveRecordMediator<Entity>.Save(savedEntity);
Flush();
// Could use FindOne, but then this test would fail if the transactions aren't being rolled back
foreach (var entity in ActiveRecordMediator<Entity>.FindAll())
{
Assert.That(entity, Is.Not.SameAs(savedEntity));
}
}
}
请注意,我使用的是带有内存数据库的自定义SQLite提供程序。我的自定义提供程序(取自)始终保持连接打开以维护架构。删除此项并使用常规SQL Server数据库不会改变行为
是否有办法实现所需的行为?对ActiveRecord不太确定,但在NHibernate中,事务属于会话,而不是相反 如果您经常使用ADO.Net,这将更有意义,因为要创建
IDbTransaction
,您需要使用连接。ActiveRecord的TransactionScope
(和NHiGenerate的ITransaction
)本质上包装了一个IDB事务
,因此您需要在TransactionScope
之前创建SessionScope
您还可能发现(取决于您使用的是NHibernate 1.2 GA还是NHibernate 2.*,以及FlushMode
您的SessionScope
所具有的功能)调用FindAll()
可能会导致会话刷新,因为NHibernate将意识到,如果不执行最后一次调用Save
,它将无法检索正确的数据
说了这么多,你是否尝试过使用
SessionScope.Flush()
而不是创建新的SessionScope
?使用SessionScope.Flush()
会使我的第三次测试失败。据我所知,Flush()
执行SQL将我的记录推入数据库,但不会从会话中逐出对象。这与您所说的导致刷新的FindAll()
相符
我真正想要的是SessionScope.Flush()
(将数据库的状态与会话同步)加上SessionScope.executeAll()
(确保在后续查询中获得新对象)。我的newsessionscope()
尝试模拟executeall()
您对包含该事务的会话的评论,而不是相反,确实给了我一个想法。我不确定在事务范围内创建一个新的会话范围
,并期望它参与事务,这有多合乎礼仪,但它似乎起到了作用:
public abstract class ARTestBase
{
private SessionScope sessionScope;
private TransactionScope transactionScope;
private bool reverse;
private IList<SessionScope> undisposedScopes;
[TestFixtureSetUp]
public void InitialiseAR()
{
ActiveRecordStarter.ResetInitializationFlag();
ActiveRecordStarter.Initialize(typeof (Entity).Assembly, ActiveRecordSectionHandler.Instance);
ActiveRecordStarter.CreateSchema();
InitialiseIoC();
undisposedScopes = new List<SessionScope>();
}
[SetUp]
public virtual void SetUp()
{
sessionScope = new SessionScope();
transactionScope = new TransactionScope(OnDispose.Rollback);
transactionScope.VoteRollBack();
base.CreateInstanceUnderTest();
reverse = false;
}
[TearDown]
public virtual void TearDown()
{
if (reverse)
{
sessionScope.Dispose();
transactionScope.Dispose();
}
else
{
transactionScope.Dispose();
sessionScope.Dispose();
}
}
[TestFixtureTearDown]
public virtual void TestFixtureTearDown()
{
foreach (var scope in undisposedScopes)
{
scope.Dispose();
}
SQLiteProvider.ExplicitlyDestroyConnection();
}
protected void Flush()
{
reverse = true;
sessionScope.Flush();
undisposedScopes.Add(sessionScope);
sessionScope = new SessionScope();
}
}
公共抽象类ARTestBase
{
非公开会议范围会议范围;
私人交易范围交易范围;
私有布尔反转;
私人IList未分解示波器;
[TestFixtureSetUp]
公共无效初始值()
{
ActiveRecordStarter.ResetInitializationFlag();
初始化(typeof(Entity.Assembly,ActiveRecordSectionHandler.Instance);
ActiveRecordStarter.CreateSchema();
InitialiseIoC();
undisposedScopes=新列表();
}
[设置]
公共虚拟空间设置()
{
sessionScope=新sessionScope();
transactionScope=新transactionScope(OnDispose.Rollback);
transactionScope.voterrollback();
base.CreateInstanceUnderTest();
反向=假;
}
[撕裂]
公共虚拟void拆卸()
{
如果(反向)
{
sessionScope.Dispose();
transactionScope.Dispose();
}
其他的
{
transactionScope.Dispose();
sessionScope.Dispose();
}
}
[测试固定器拆卸]
公共虚拟void TestFixtureTearDown()
{
foreach(undisposedScopes中的var范围)
{
scope.Dispose();
}
SQLiteProvider.ExplicitlyDestroyConnection();
}
受保护的空刷新()
{
反向=真;
sessionScope.Flush();
添加(会话范围);
sessionScope=新sessionScope();
}
}
进一步考虑,这将不允许您在每个测试用例中刷新超过一次。我想我可以通过更仔细地跟踪示波器来处理这个问题。我可能以后再调查
public abstract class ARTestBase
{
private SessionScope sessionScope;
private TransactionScope transactionScope;
private bool reverse;
private IList<SessionScope> undisposedScopes;
[TestFixtureSetUp]
public void InitialiseAR()
{
ActiveRecordStarter.ResetInitializationFlag();
ActiveRecordStarter.Initialize(typeof (Entity).Assembly, ActiveRecordSectionHandler.Instance);
ActiveRecordStarter.CreateSchema();
InitialiseIoC();
undisposedScopes = new List<SessionScope>();
}
[SetUp]
public virtual void SetUp()
{
sessionScope = new SessionScope();
transactionScope = new TransactionScope(OnDispose.Rollback);
transactionScope.VoteRollBack();
base.CreateInstanceUnderTest();
reverse = false;
}
[TearDown]
public virtual void TearDown()
{
if (reverse)
{
sessionScope.Dispose();
transactionScope.Dispose();
}
else
{
transactionScope.Dispose();
sessionScope.Dispose();
}
}
[TestFixtureTearDown]
public virtual void TestFixtureTearDown()
{
foreach (var scope in undisposedScopes)
{
scope.Dispose();
}
SQLiteProvider.ExplicitlyDestroyConnection();
}
protected void Flush()
{
reverse = true;
sessionScope.Flush();
undisposedScopes.Add(sessionScope);
sessionScope = new SessionScope();
}
}