Hi,

I get an exception with private constructors (this was working before)

Version: 4.3.1 build 1.0.5680.9042

[Serializable]
  [HierarchyRoot]
  public class MyEntity : Entity
  {
    public static MyEntity CreateInstance()
    {
      return new MyEntity();
    }

    private MyEntity()
    {

    }

    [Field, Key]
    public int Id { get; private set; }
  }

using (Session.Open(domain))
      {
        using (var transactionScope = Transaction.Open())
        {
          MyEntity.CreateInstance();

          transactionScope.Complete();
        }
      }

System.InvalidOperationException was unhandled
  Message=Can not commit a transaction: ValidationContext is in inconsistent state.
  Source=Xtensive.Storage
  StackTrace:
       at Xtensive.Storage.Transaction.CompleteValidation()
       at Xtensive.Storage.Transaction.Commit()
       at Xtensive.Storage.TransactionScope.Dispose()

This is not an urgent problem for us, but a fix would be nice.

Julien

This thread was imported from our support forum. The original discussion may contain more detailed answer.

asked Aug 17 '10 at 09:22

olorin's gravatar image

olorin
358878792

edited Sep 03 '10 at 16:27

Alex%20Yakunin's gravatar image

Alex Yakunin
29714412

I accepted my own answer to close the topic. Hopefully, it was helpful...

(Sep 03 '10 at 16:28) Alex Yakunin Alex%20Yakunin's gravatar image

One Answer:

You can't call private constructors directly - they can be called only from other constructors. So you need internal or protected constructor here.

The problem is pretty complex: actually, DO4 has few requirements to descendants of Entity and Structure constructors:

  • Private constructors can be called only from other constructors.

  • Non-private constructors in the same type may not call each other, but may call private constructors in the same type.

The issue is related to constructor call interception. We can't use regular method call interception in this case (as with other methods), since base .ctor is always called first (otherwise class won't pass verification), and thus auto transaction must be created inside it, so we developed a special aspect (InitializableAttribute) to support this case. It injects special prologue and epilogue in each constructor to make interception work, but, apparently, the approach we invented can't work if such "transactional .ctors" in the same type call each other (we simply can't detect the boundaries here - at least, in some cheap way; see the IL code we inject, it explains, why, but this is pretty trick case). On the other hand, if "transactional .ctor" calls "non-transactional .ctor" in the same type, it's absolutely ok.

So that's why we do not convert private .ctors to transactional: in this case it will be possible to call them from other .ctors. Moreover, private .ctors are frequently used exactly by this way - so that was also +1 for doing this.

answered Aug 17 '10 at 14:12

Alex%20Yakunin's gravatar image

Alex Yakunin
29714412

Btw, this isn't a very strong limitation, so actually, we aren't going to fix this (moreover, I don't know a good way of doing this).

But it is one of unexpected things you should be aware of in case with DO.

(Aug 17 '10 at 14:12) Alex Yakunin Alex%20Yakunin'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

powered by OSQA