Continuing with my tests to use DataObjects.NET on my next product development, I started to face some weird session behavior while handling Domain entities in my Presenter layer. Before raising a question here, I decided to test some specific session / transaction behavior to check whether I was correctly understanding their implementation. The results puzzled me.

Here's the scenario:

(1) Two very simple entities:

[HierarchyRoot]
public class Entity2 : Entity
{
    [Field, Key]
    public Int32 Id { get; private set; }

    [Field]
    public String Name { get; set; }

}

[HierarchyRoot]
public class Entity1 : Entity
{
    [Field, Key]
    public Int32 Id { get; private set; }

    [Field]
    public String Name { get; set; }

    [Field]
    public EntitySet<Entity2> Two { get; set; }
}

(2) A very simple console application manipulating everything on its Main method:

static void Main(string[] args)
    {
        DateTime firstLine = DateTime.Now;

        //Simple configuration, straight forward SQL Server Express with Recreate option
        DomainConfiguration config = new DomainConfiguration("sqlserver",
                      "Data Source=localhost\\SQLEXPRESS; Initial Catalog=NewTemp; " +
                      "Integrated Security=True; MultipleActiveResultSets=true;")
        {
            UpgradeMode = DomainUpgradeMode.Recreate
        };

        config.Types.Register(typeof(Domain.Entity1).Assembly, typeof(Domain.Entity1).Namespace);

        //Three domains for testing purposes, from what I've seen, results seem invariant using 1, 2 or 3 domains.
        Xtensive.Orm.Domain firstDomain = Xtensive.Orm.Domain.Build(config);
        Xtensive.Orm.Domain aDomain = Xtensive.Orm.Domain.Build(config);
        Xtensive.Orm.Domain anotherDomain = Xtensive.Orm.Domain.Build(config);

        //This firstSession was created just to populate some "Entity2" entities into the database first.
        var firstSession = firstDomain.OpenSession();
        firstSession.Activate();
        var firstTransaction = firstSession.OpenTransaction();

        Domain.Entity2 anEntity2 = new Domain.Entity2();
        anEntity2.Name = "First";

        Domain.Entity2 anotherEntity2 = new Domain.Entity2();
        anotherEntity2.Name = "Second";

        firstTransaction.Complete();
        firstTransaction.Dispose();
        firstSession.Dispose();
        firstDomain.Dispose();
        //This is as far as the firstSession, firstSession and firstTransaction go. They were used just to populate initial data

        //This is where the actual test start. The objetive is to create a new Entity1, attach an Entity2 to it and don't commit it.
        var aSession = aDomain.OpenSession(); 
        aSession.Activate();
        var aTransaction = aSession.OpenTransaction(); 
        Domain.Entity1 anEntity1 = new Domain.Entity1();
        anEntity1.Name = "One";
        anEntity1.Two.Add(aSession.Query.All<Domain.Entity2>().Single<Domain.Entity2>(e2 => e2.Name == "First")); //<IMPORTANT POINT 1> From THIS line and on, there seem to be a lock on table Entity1 and I can't even query it straight from SQL Server Management Studio. There seem to be no lock on the table Entity2 neither on the Many-to-Many Entity1-Two-Entity2 table.
        //Up to this point, no commits on aTransaction.

        //Now, the second part. In another transaction, another session, another domain, while the previous transaction is still opened, execute a very similar creation creation and don't commit it.
        var anotherSession = anotherDomain.OpenSession(); //from my testing, this works just the same if I use the same "aDomain" from the other part. Also, it seem to work the same if I use the same session instead of creating another one.
        anotherSession.Activate();
        var anotherTransaction = anotherSession.OpenTransaction();
        Domain.Entity1 anotherEntity1 = new Domain.Entity1();
        anotherEntity1.Name = "Two";
        anotherEntity1.Two.Add(aSession.Query.All<Domain.Entity2>().Single<Domain.Entity2>(e2 => e2.Name == "First"));
        //Up to this point, no commits on anotherTransaction.

        //Now I'll commit both transactions, starting from the first one.
        aTransaction.Complete();
        aTransaction.Dispose();
        //<IMPORTANT POINT 2> From THIS line and on, the lock seem to be released and I can once again query Entity1 table straight from SQL Server Management Studio
        anotherTransaction.Complete();
        anotherTransaction.Dispose();
        //After the second commit, both Entity1 entities I created are persisted, as are their relationships with the Entity2.
    }

I tried to verbosely comment the tests above to better communicate my intention. After these tests, my doubts:

(1) Why is the "lock" just applied to "Entity1" table? Why not "Entity2" and "Entity1-Two-Entity2" tables?

(2) Why is the "lock" applied on that particular line (i.e. when adding the relationship with Entity2)?

(3) Why isn't the second transaction subject to a similar lock? Why identical (at least in my point of view) codes generate different lock behavior on the database?

Thanks in advance!

Pedro Góes

asked Jun 12 '12 at 11:22

pgoes's gravatar image

pgoes
216610

edited Jun 12 '12 at 11:27

Hello Pedro,

Thank for the sample. We'll check this and post an answer.

(Jun 14 '12 at 08:19) Dmitri Maximov Dmitri%20Maximov's gravatar image

One Answer:

(1) Why is the "lock" just applied to "Entity1" table? Why not "Entity2" and "Entity1-Two-Entity2" tables?

DataObjects.Net does not lock entities on it-self, it relies on DBMS and its transaction isolation facilities. According to your examples it seems that you did not enable snapshot isolation. Inserting single row into empty table will likely to cause whole table to be locked due to lock escalation.

(2) Why is the "lock" applied on that particular line (i.e. when adding the relationship with Entity2)?

When you execute a query DataObjects.Net will flush changes to database. Entity1 is inserted just before your query for Entity2. Relation Entity1-Two-Entity2 is created after your query, that is why it is not locked on that line. It is not saved yet.

(3) Why isn't the second transaction subject to a similar lock? Why identical (at least in my point of view) codes generate different lock behavior on the database?

You have a typo in your example you use aSession for querying instead of anotherSession. This means Entity1 from anotherSession is not saved at that moment and thus it's not locked.

answered Jun 19 '12 at 07:40

Denis%20Krjuchkov's gravatar image

Denis Krjuchkov
179325

Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

powered by OSQA