1

我正面临存储库和事务的异常行为,这让我很生气。

我有两个简单的 POCO 类 Action 和 Version 如下。Action->Version 是一对多的关系。

public class Action : Entity
{
    public virtual string Name
    {
        get;
        set;
    }

    public virtual IList<Version> Versions
    {
        get;
        protected set;
    }

    public Action()
    {
        Versions = new List<Version>();
    }

    public virtual void AddVersion( Version version )
    {
        version.Action = this;
        Versions.Add( version );
    }
}

public class Version : Entity
{

    public virtual int Number
    {
        get;
        set;
    }

    public virtual Action Action
    {
        get;
        set;
    }

    public Version()
    {
    }
}

现在我有一个代码段如下:

    var actionRep = new Repository<Action>();
    var versionRep = new Repository<Version>();

    var act1 = new Action( );
    actionRep .SaveOrUpdate( act1 );

    using (versionRep .DbContext.BeginTransaction())
    {

        var v1 = new Version();
        act1.AddVersion( v1 );
        //versionRep .SaveOrUpdate( v1 );
        versionRep .DbContext.CommitTransaction();
    }

在上面的代码中,我只是创建了 Action 和 Version 存储库。首先,我使用 Action Repository 持久化一个 Action 对象。然后我使用 Version repository 开始一个事务,创建一个新版本,使用 Action 设置引用,并在没有实际调用 Version Repository 的情况下提交事务。

结果有点奇怪。即使我没有在版本存储库上调用 SaveOrUpdate 方法,版本对象也会被保留。如果我注释掉行 act1.AddVersion( v1 ); 在事务中,则版本不会被持久化。

经过一番努力,我直接使用 NHibernate 测试了相同的场景,而不是使用相同的流畅映射/配置 (AutoPersistenceModelGenerator.Generate()) 使用 Sharp Architecture 存储库。结果和预期的一样。版本对象不会被持久化。这是代码

    var sessionFactory = CreateSessionFactory();
    _act1 = new Action();

    using( var session = sessionFactory.OpenSession() )
    {
        session.SaveOrUpdate( _act1 );
    }

    using( var session = sessionFactory.OpenSession() )
    {
        using (var transaction = session.BeginTransaction())
        {
            _v1 = new Version();
            _act1.AddVersion( _v1 );
            //session.SaveOrUpdate( _act1 );
            transaction.Commit();
        }
    }

CreateSessionFactory() 方法如下。没什么复杂的

        private const string _dbFilename = "nhib_auditing.db";
        private static ISessionFactory CreateSessionFactory()
        {
            return Fluently.Configure()
                .Database( SQLiteConfiguration.Standard
                            .UsingFile( _dbFilename )
                            .ShowSql())
                .Mappings( m => m.AutoMappings.Add( new
AutoPersistenceModelGenerator().Generate() ) )
                .ExposeConfiguration( BuildSchema )
                .BuildSessionFactory();
        }

现在,如果有人可以请让我知道我为什么会有这种行为。它让我很生气。

只是为了让您知道我也没有覆盖 Action 和 Version 的映射。

等待纳比尔

4

2 回答 2

4

如果您在映射中声明了级联操作,这是预期的行为。当您调用SaveOrUpdateact1 时,您使瞬态对象持久化;也就是说,NHibernate 正在跟踪它,并在会话刷新时保存它。使对象持久化的另一种方法是将其与持久化对象相关联,就像您在调用act1.AddVersion( v1 );. 提交事务时刷新了会话,因此保存了 v1。本文解释了使用持久对象的细节。

于 2010-06-22T22:41:24.970 回答
0

顺便说一下,这是我的两个测试,一个是 SharpRepositories 失败,另一个是 NHibernate Direct,它正在通过。

    [TestFixture]
    public class RepositoryTests : RepositoryTestsBase
    {
        protected override void LoadTestData()
        {
        }

        [Test]
        public void TestUsingSharpRespositories
        {
            var aRep = new Repository<Action>();
            var vRep = new Repository<Version>();

            _act1 = new Action();
            aRep.SaveOrUpdate( _act1 );

            using( vRep.DbContext.BeginTransaction() )
            {
                _v1 = new Version();
                _act1.AddVersion( _v1 );
                //vRep.SaveOrUpdate(_v1);
                vRep.DbContext.CommitTransaction();
            }
            _v1.IsTransient().ShouldBeTrue();
        }

        [Test]
        public void TestUsingNHibernateSession
        {
            var sessionFactory = CreateSessionFactory();
            _act1 = new Action();

            using( var session = sessionFactory.OpenSession() )
            {
                session.SaveOrUpdate( _act1 );
            }

            using( var session = sessionFactory.OpenSession() )
            {
                using (var transaction = session.BeginTransaction())
                {
                    _v1 = new Version();
                    _act1.AddVersion( _v1 );

                    transaction.Commit();
                }
            }

            _v1.IsTransient().ShouldBeTrue();
        }

        private const string _dbFilename = "nhib_db.db";
        private static ISessionFactory CreateSessionFactory()
        {
            return Fluently.Configure()
                .Database( SQLiteConfiguration.Standard
                            .UsingFile( _dbFilename )
                            .ShowSql())
                .Mappings( m => m.AutoMappings.Add( new
AutoPersistenceModelGenerator().Generate() ) )
                .ExposeConfiguration( BuildSchema )
                .BuildSessionFactory();
        }

        private static void BuildSchema( Configuration config )
        {
            if( File.Exists( _dbFilename ) )
                File.Delete( _dbFilename );
            new SchemaExport( config ).Create( false, true );
        }
    }

我是 Fluent NHibernate 的新手,我从未直接将 NHibernate 与 xml 映射一起使用。

就映射而言,我使用的是在 Visual Studio 中创建新的 Sharp Architecture 项目时设置的 vanilla 自动映射配置。我有一个 HasMany 的约定如下:

public class HasManyConvention : IHasManyConvention
    {
        public void
Apply( FluentNHibernate.Conventions.Instances.IOneToManyCollectionInstance
instance )
        {
            instance.Key.Column( instance.EntityType.Name + "Fk" );
            instance.Inverse();
            instance.Cascade.All();
        }
    } 

我按如下方式更新了我的 TestUsingNHibernateSession 测试,以测试我在单个会话中同时操作 Action 和 Version 时它的行为。你猜怎么着,版本对象被保存了,即使在事务的开始和提交之间没有任何东西。

    [Test]
    public void TestUsingNHibernateSession
    {
        var sessionFactory = CreateSessionFactory();
        _act1 = new Action();

        using( var session = sessionFactory.OpenSession() )
        {
            session.SaveOrUpdate( _act1 );
        //}

        //using( var session = sessionFactory.OpenSession() )
        //{
            _v1 = new Version();
            _act1.AddVersion( _v1 );
            using (var transaction = session.BeginTransaction())
            {
                transaction.Commit();
            }
        }

        _v1.IsTransient().ShouldBeTrue();
    }

所以我的结论是这一切都与会议有关。如果在会话中创建或检索了对象 A,然后如果在该会话中开始新事务,则一旦提交该事务,与对象 A 关联的所有瞬态或脏对象也将被保存,不会无论对象是在 Begin 和 Commit 内部还是外部创建的。

如果他们同意我的理解,谁能告诉我?而且我还假设夏普架构在每个网络请求中都使用单个休眠会话?

等待纳比尔

于 2010-06-22T22:07:09.813 回答