S#arp Architecture Repository.DbContext.CommitTransaction() 异常行为

发布于 2024-09-07 00:01:17 字数 2770 浏览 5 评论 0原文

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

我有两个简单的 POCO 类 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 Repository 保存一个 Action 对象。然后我开始 使用版本存储库的事务,创建新版本,设置 引用操作,并提交事务而不 实际上调用版本存储库。

结果有点奇怪。版本对象甚至会被持久化 虽然我没有在版本存储库上调用 SaveOrUpdate 方法。如果 我注释掉了 act1.AddVersion( v1 ); 行在交易内, 那么版本不会被持久化。

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

    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 和 版本也可以。

等待中 纳比尔

I am facing an unusual behaviour with the Repository and Transactions
and its making me mad.

I have two simple POCO classes Action and Version as follows. There is
a one to many relationship from 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()
    {
    }
}

Now I have a code segment as follows:

    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();
    }

In the above code I am just creating Action and Version repositories.
First I persist an Action object using Action Repository. Then I begin
a transaction using Version repository , create a new version, set
references with the Action, and Commit the transaction without
actually calling Version Repository.

The result is a bit strange. The version object gets persisted even
though I have not called SaveOrUpdate method on version repository. If
I comment out the line act1.AddVersion( v1 ); within the transaction,
then the Version does not get persisted.

After a bit of struggle I tested the same scenario using NHibernate
directly instead of using Sharp Architecture repositories using same
fluent mapping/configuration
(AutoPersistenceModelGenerator.Generate()). And The result is as
expected. The version object does not get persisted. Here is the code

    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();
        }
    }

The CreateSessionFactory() method is as follows. Nothing complicated

        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();
        }

Now If sombody could please let me know why I am having this
behaviour. Its making me mad.

Just so that you know I have not overridden mapping for Action and
Version either.

Awaiting
Nabeel

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

゛时过境迁 2024-09-14 00:01:17

如果您在映射中声明了级联操作,则这是预期的行为。当您在 act1 上调用 SaveOrUpdate 时,您使瞬态对象变得持久化;也就是说,NHibernate 正在跟踪它,并会在会话刷新时保存它。使对象持久化的另一种方法是将其与持久对象关联起来,就像调用 act1.AddVersion( v1 ); 时所做的那样。提交事务时会话被刷新,因此 v1 被保存。 本文介绍了详细信息与持久对象一起工作。

This is the expected behavior if you have cascading operations declared in the mapping. When you called SaveOrUpdate on act1 you made the transient object persistent; that is, NHibernate is tracking it and will save it when the session is flushed. Another way to make an object persistent is to associate it with a persistent object, as you did when you called act1.AddVersion( v1 );. The session was flushed when the transaction was committed so v1 was saved. This article explains the details of working with persistent objects.

鸠魁 2024-09-14 00:01:17

顺便说一句,这是我的两个测试,其中一个是使用 SharpRepositories
失败,然后使用 NHibernate Directly 正在通过。

    [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 项目时设置的。我对 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 内部还是外部创建的。

如果有人同意我的理解,可以告诉我吗?我还假设 Sharp 架构在每个 Web 请求中使用单个 nhibernate 会话?

等待中
纳比尔

By the way, Here are my two tests one with SharpRepositories which is
failing and the ther with NHibernate Directly which is passing.

    [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 );
        }
    }

I am new to Fluent NHibernate and I have never used NHibernate directly with xml mapping.

As far as mapping is concerned, I am using vanilla automapping configuration that is setup when you create a new Sharp Architecture project in visual studio. I have a convention for HasMany as follows:

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

I updated my TestUsingNHibernateSession test as follows to test how it behaves if I manipulate both Action and Version in a single session. And guess what, the Version object gets saved, even though there is nothing between the Transaction's begin and commit.

    [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();
    }

So my conclusion is that its all to do with the Session. If an object A has been created or retrieved in a session and then later on if a new transaction begins within that session, then as soon as that transaction is commited, all the transient or dirty objects associated with object A gets saved as well, no matter wether objects gets created within or outside of Begin and Commit.

Could anyone please let me know if they agree with my understanding? And I am also assuming that Sharp architecture uses a single nhibernate Session throughtout each web request?

Awaiting
Nabeel

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文