Search code examples
nhibernatefluent-nhibernates#arp-architectureautomapping

S#arp Architecture Repository.DbContext.CommitTransaction() unusual behaviour


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


Solution

  • 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.