Detach, ObjectScope and InvalidOperationException.

4 posts, 2 answers
  1. Jose Mejia
    Jose  Mejia avatar
    107 posts
    Member since:
    May 2009

    Posted 30 Oct 2012 Link to this post

    Hello.

    Suppose the following code:

    MainEntity mainE;
     MainEntity newmainE;
      using (TestBenchModel model = new TestBenchModel())
        {
       mainE = model.MainEntities.SingleOrDefault(t => t.MainId == 10);
         newmainE = model.CreateDetachedCopy(mainE, t=>t.Helper1,t=>t.Properties);
      }
     
     
     
    newmainE.Value = new Random().Next().ToString();
     
     using (TestBenchModel model = new TestBenchModel())
     {
        MainEntity mainEntity = new MainEntity { Value = "123456" };
        foreach (var helper1 in newmainE.Helper1)
         {
            mainEntity.Helper1.Add(helper1);
          }
        foreach (var prop in newmainE.Properties)
          {
            mainEntity.Properties.Add(prop);
          }
     
         model.AttachCopy(mainEntity);

    I've got the following exception:
    Telerik.OpenAccess.Exceptions.InvalidOperationException was unhandled
      Message=Object references between two different object scopes are not allowed. The object 'OAEagerLoadingTest.Helper1' is already managed by 'ObjectScopeImpl 0x2' and was tried to be managed again by 'ObjectScopeImpl 0x4'.


    Why I'm getting this execption, because  the state oh Helper1 entities is DetachedClean?
    Or newMain.Helper1 values and newMain.Properties are linked only to newMain object (belong to newMain object scope???), so I can't use them with other objects?

    Thanks in advance.
  2. Answer
    Thomas
    Admin
    Thomas avatar
    590 posts

    Posted 31 Oct 2012 Link to this post

    Hi Jose,

    you are creating cross-references between the fresh mainEntity instance and the parts of the detached graph from the newmainE instance. During AttachCopy the fresh mainEntity is then transitivly referencing the detached instances, and this is currently not supported.
    What you can do is to create a fresh mainEntity with the new Value, Add() that to the context. Then perform the AttachCopy of the newmainE, and set the return value as the mainEntity.Helper1 value. Likewise for the properties. This guarantees us that all references are within one context at the end.

    Regards,
    Thomas
    the Telerik team
    Telerik OpenAccess ORM Meets ASP.NET Web API. Read more.
  3. DevCraft banner
  4. Jose Mejia
    Jose  Mejia avatar
    107 posts
    Member since:
    May 2009

    Posted 31 Oct 2012 Link to this post

    Hello, Thomas .

    Your solution seems to work, but if association property IsManaged = true  on Target  side,
    then the following code:

    using (TestBenchModel model = new TestBenchModel())
     {
         MainEntity mainEntity = new MainEntity { Value = "123456" };
         model.Add(mainEntity);
                   
         newmainE = model.AttachCopy(newmainE);
     
        foreach (var helper1 in newmainE.Helper1)
        {
           mainEntity.Helper1.Add(helper1);
        }

    in foreach loop on second iteration throws:

    System.InvalidOperationException was unhandled
      Message=Collection was modified; enumeration operation may not execute.

    If IsManaged set to false then it seems to work.
    Is it bug or it is expected behavior? What if I need to keep IsManaged = true?

    Thanks in advance.
  5. Answer
    Thomas
    Admin
    Thomas avatar
    590 posts

    Posted 01 Nov 2012 Link to this post

    Hello Jose,

    the IsManaged property tells the foreign-key collection to maintain the inverse reference in the other side; effectively freeing the user from doing that job. So when an OrderDetail is added to the details collection of the Order, the runtime will modify the OrderDetails order reference.
    I think this happens regardless of the context the instance is bound to, and in such code as yours, the automatism of this might bite you.
    The exception you are getting now is a different one: By logically modifying the collection while enumerating it the enumeration process fails. This happens also for pur CLR collections! You will need to create a copy (.ToList()) before you perform the .Add(helper1).

    Regards,
    Thomas
    the Telerik team
    Telerik OpenAccess ORM Meets ASP.NET Web API. Read more.
Back to Top