7

我正在学习一些 Fluent NHibernate,并且遇到了半真棒 PersistenceSpecification 类。

我已经在单元测试中设置它来验证我的映射并且效果很好。但是,它在完成后将记录留在数据库中。我尝试将其放入事务中,以便回滚更改,但出现错误:

System.ObjectDisposedException:无法访问已处置的对象。对象名称:'AdoTransaction'..

如果没有事务,我必须找出记录的 ID,检索它们并删除它们,这似乎不太优雅。

有什么想法吗?

编辑:

这是代码片段:

            var factory = GetSessionFactory();
            using (var session = factory.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                new PersistenceSpecification<TimePeriod>(session)
                        .CheckProperty(x => x.EndDate, DateTime.Today)
                        .VerifyTheMappings();
                transaction.Rollback();
            }
4

5 回答 5

9

尝试在事务上设置 IsolationLevel。这个片段对我有用:

using (var trans = _session.BeginTransaction(IsolationLevel.ReadUncommitted))
{
    new PersistenceSpecification<Event>(_session)
        .CheckProperty(p => p.StartTime, new DateTime(2010, 1, 1))
        .VerifyTheMappings();
    trans.Rollback();
}
于 2010-01-03T10:27:02.197 回答
2

PersistenceSpecification通常与 SQLite 等内存数据库一起使用,这就是它不回滚任何内容的原因。我相信有一个构造函数重载需要一个ISession实例,您是否尝试过从那里获取事务然后将其回滚?

于 2009-03-11T08:53:40.053 回答
2

我认为这里的问题是 VerifyTheMappings() 调用 TransactionSave() 对数据库执行 tx.Commit() 。正如 James 所指出的,这种技术似乎非常适合丢弃内存测试技术。这在针对遗留数据库测试映射的情况下不起作用

于 2009-06-18T01:19:07.307 回答
1

设置IsolationLevel.ReadUncommitted将起作用,但只是顺便说一句,因为它所做的只是告诉会话它可以在不需要新事务的情况下读取(用 DBMS 的说法是脏读) - 因此Session.Transaction.Commit ()不必在验证读取之前提交数据库事务. 这也意味着它不一定是在测试你认为它正在测试的东西!(我也认为这在非​​ MS SQL 数据库中可能有问题的支持)。leebrandt 的答案之所以有效,是因为显式回滚,而不是隔离级别(注意。在回答时,这比现在更有帮助,请参见下面的注释)。

好消息是正确的方法是手动回滚事务。Session.Transaction每当提交事务时都会自动替换,因此您需要保留对它的引用,并且无论如何您都必须显式打开一个,因为TransactionalSave ()检查当前事务是否处于活动状态并创建(并处置!)它自己的 if不是。我通常在同一个夹具中测试我的所有映射,在那里我还验证了工厂创建和其他一些基础设施持久性的东西,所以我喜欢下面的模式来减少管道:

class TestFixture {
    static ISessionFactory factory = CreateMyFactorySomehowHere();

    ISession session;
    ITransaction tx;

    public void Setup ()
    {
        session = factory.OpenSession ();
        tx = session.BeginTransaction ();
    }

    public void Cleanup ()
    {
        tx.Rollback ();
        tx.Dispose ();
        session.Close ();
    }

    public void TestAMappingForSomething ()
    {
        var spec = new PersistenceSpecification<Something> (session);
        spec.VerifyTheMappings ();
    }
}

显然,在任何地方插入您自己的特定于测试框架的术语和属性/注释,但您明白了。


我刚刚注意到这个问题有多老了:此行为已在 7 月 9 日的此提交中修复,以很好地处理现有事务,以便上述工作!显然,无论如何,这就是您最初所做的。

于 2011-03-09T03:06:26.050 回答
0

我认为使用您的真实数据库进行此测试非常重要,以查看他的表定义是否正常,因此我开发了一个非常简单的类,该类对映射实体执行粗略测试并在最后回滚;

 internal class GenericMappingTesterWithRealDB<T> where T : IIdentifiable
{
    public T EntityToTest { get; set; }
    public Func<T, object> PerformEntityManipulationBeforeUpdate { get; set; }
    public GenericMappingTesterWithRealDB()
    {
        Assume.That(SessionFactoryProvider.NewSession,Is.Not.Null);
    }

    public void RunTest()
    {
        using (ISession session = SessionFactoryProvider.NewSession)
        using (ITransaction transaction = session.BeginTransaction())
        {
            try
            {
                session.Save(EntityToTest);
                var item = session.Get<T>(EntityToTest.ID);
                Assert.IsNotNull(item);
                if (PerformEntityManipulationBeforeUpdate != null)
                {
                    PerformEntityManipulationBeforeUpdate.Invoke(EntityToTest);
                }
                session.Update(EntityToTest);
                session.Delete(EntityToTest);
                session.Save(EntityToTest);
            }
            catch (Exception e)
            {
                Assert.Fail(e.Message, e.StackTrace);
            }
            finally
            {
                transaction.Rollback();
            }
        }
    }
}

在我的项目中可以识别的是我的实体的最基本的接口

该课程正在使用 nunit.framework 但您可以使用您想要的每个测试框架来完成

sessionfactoryprovider 需要提供 isession obj

这是一个使用示例

/// <summary>
/// Testing the mapping of our entities.
/// there must be a server connection for this kind of test.
/// </summary>
[TestFixture]
internal class someMappingTest
{
    [Test(Description = "Check the Encoding Profile FluentNHibernate Mapping")]
    [Timeout(20000)]
    public void checkthatMappingWorks()
    {
        // creatw the new entity
        TestedType testOn = new TestedType();

        // set the initialization values
        testOn.Name = "TestProfileExecution";

        // create the test object
        new GenericMappingTesterWithRealDB<TestedType>
        {
            // assign an entity
            EntityToTest = testOn,

            // assign new values for update check
            PerformEntityManipulationBeforeUpdate =
                delegate(TestedType testedTypeBeingTested)
                    {
                        return testedTypeBeingTested.Name = "Updateing Test";
                    }
        }.
        // call run test to perform the mapping test.
        RunTest();

    }
}
于 2009-08-15T14:29:04.467 回答