Hi,

I have the following exception with DataObjects 5.

Call stack :

Result Message: Test method UnitTests.Orm.DataObjects.TestTransactionRollback threw exception: System.InvalidOperationException: Can not persist: there are pinned entities. Result StackTrace:
at Xtensive.Orm.Session.Persist(PersistReason reason) at Xtensive.Orm.Session.CommitTransaction(Transaction transaction) at Xtensive.Orm.Transaction.Commit() at Xtensive.Orm.TransactionScope.Dispose() at UnitTests.Orm.DataObjects.TestTransactionRollback() in c:\Work-Dev\aradus\Projets\DonatelloBranches\DataObjects5\UnitTests\Orm\DataObjects.cs:line 85

Here the code to reproduce it :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Xtensive.Orm;
using Xtensive.Orm.Configuration;

    namespace UnitTests.Orm
    {
      [TestClass]
      public class DataObjects
      {
        [TestMethod, TestCategory("Transaction.Rollback")]
        public void TestTransactionRollback()
        {
          Domain domain = CreateDomain(SessionOptions.ValidateEntities | SessionOptions.AutoActivation | SessionOptions.NonTransactionalReads);
          using (Session session = domain.OpenSession())
          {
            Assert.IsTrue(!Query.All<TestEntity>().Any(), "TestEntity table should be empty");
            using (TransactionScope t = session.OpenTransaction())
            {
              new TestEntity(session);
              // transaction not committed : will be rolled back
            }
            Assert.IsTrue(!Query.All<TestEntity>().Any());
            using (TransactionScope t = session.OpenTransaction())
            {
              new TestEntity(session) { MyValue = 1000 };
              t.Complete();
            }

            Assert.IsTrue(Query.All<TestEntity>().Count() == 1);
            Assert.IsTrue(Query.All<TestEntity>().Single().MyValue == 1000);
            using (TransactionScope t = session.OpenTransaction())
            {
              Query.All<TestEntity>().Single().MyValue = 2000;
              // transaction not committed : will be rolled back
            }

            Assert.IsTrue(Query.All<TestEntity>().Single().MyValue == 1000);
          }
        }

        private Domain CreateDomain(SessionOptions sessionOptions)
        {
          string connectionString = Configuration.Instance.DataObjectsConnectionString;
          var config = new DomainConfiguration(connectionString);
          config.UpgradeMode = DomainUpgradeMode.Recreate;
          config.Types.Register(typeof(TestEntity));
          SessionConfiguration defaultSessionConfig = config.Sessions.Default;
          if (defaultSessionConfig == null)
          {
            defaultSessionConfig = new SessionConfiguration(WellKnown.Sessions.Default);
            config.Sessions.Add(defaultSessionConfig);
          }

          defaultSessionConfig.Options = sessionOptions;
          return Domain.Build(config);
        }
      }
    }

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

        [Field]
        public long MyValue { get; set; }

        public TestEntity(Session session)
          : base(session)
        {
        }
      }

Could you have a look ? Thanks, Benoit

asked Aug 29 '16 at 11:08

Benoit%20Nesme's gravatar image

Benoit Nesme
43202024

The exception will happen when disposing the second transaction, after the call of t.Complete().

(Aug 29 '16 at 11:09) Benoit Nesme Benoit%20Nesme's gravatar image

One Answer:

Hello Benoit Nesme

Thank you for the good example. The problem here is in SessionOptions you declared. As I remember you are migrating from 4.6.x to 5.0.x now. Please, post session options you had in 4.6 and I will guide you which options you need to set in 5.0.x.

answered Aug 29 '16 at 11:40

Alexey%20Kulakov's gravatar image

Alexey Kulakov
77225

edited Aug 29 '16 at 11:41

In DO 4.6 we are using SessionOptions.LegacyProfile only, but it doesn't exist in DO5.

(Aug 29 '16 at 11:50) Benoit Nesme Benoit%20Nesme's gravatar image

It has legacy profile but it was changed. DO can work in one of two main behaviors. DO can save changes before any query to make sure results will contain new or changed data OR DO can let you full control when it will save data by manual Session.SaveChanges() operation. Which scenario is closer to you?

(Aug 29 '16 at 12:03) Alexey Kulakov Alexey%20Kulakov's gravatar image

Hi Alexey,

We basically want the same behaviour as in DO4.6 using LegacyProfile Our product has more than 1000 entities managed with dataobjects, and the code base is quite big. So the less changes in session/transaction pattern the better.

(Aug 30 '16 at 04:31) Benoit Nesme Benoit%20Nesme's gravatar image

Try to use such options combination - SessionOptions.LegacyProfile | SessionOptions.AutoSaveChanges. Legacy profile already contains SessionOptions.ValidateEntities and SessionOptions.AutoActivation. SessionOptions.AutoSaveChanges allows DO to manage when changes should be persisted. Basically, with this option DO will persist data almost every time when you query some data from DB to keep DB state in accordance with Entities' states.

Unfortunately, we removed SessionOption.AutoTransactionOpenMode so you will have to open it manually.

(Aug 30 '16 at 05:48) Alexey Kulakov Alexey%20Kulakov's gravatar image

SessionOptions.NonTransactionalReads makes DO not to attach entities to transaction as it normally does. So you don't have to open a transaction to query some data. With this option DO attaches Entities to a session instance and it prevents them from invalidation after leaving transaction scope. You are still able to open transaction if you need to, but you don't have to do it. Probably it might be useful for you.

(Aug 30 '16 at 05:55) Alexey Kulakov Alexey%20Kulakov's gravatar image

Ok, it's where we are at the moment : SessionOptions.LegacyProfile | SessionOptions.AutoSaveChanges | SessionOptions.NonTransactionalReads.

We are having a strange bug and I suspected AutoSaveChanges that's why my sample didn't have it, I was testing without it.

We are using NonTransactionalReads because it's closed to AutoTransactionOpenMode (for reads at least)

For information, what would need to be done to make the 1st sample work ? calling session.SaveChanges ? if so, where ?

(Aug 30 '16 at 07:04) Benoit Nesme Benoit%20Nesme's gravatar image

What bug do you mean?

(Aug 30 '16 at 07:06) Alexey Kulakov Alexey%20Kulakov's gravatar image

I am investigating the bug at the moment : it appears after migrating to DO5, however I cannot reproduce it yet.

(Aug 30 '16 at 07:43) Benoit Nesme Benoit%20Nesme's gravatar image

Is it the bug you reported here recently?

(Aug 30 '16 at 07:54) Alexey Kulakov Alexey%20Kulakov's gravatar image

I have opened a new support ticket to report the bug as it's a different bug from this one. http://support.x-tensive.com/question/6445/do5-bug-transaction-not-roll-backing-under-certains-conditions

(Aug 30 '16 at 09:43) Benoit Nesme Benoit%20Nesme's gravatar image
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

Subscription:

Once you sign in you will be able to subscribe for any updates here

Tags:

×4
×1
×1

Asked: Aug 29 '16 at 11:08

Seen: 3,425 times

Last updated: Aug 30 '16 at 09:43

powered by OSQA