none
Is this the right way to get a detached entity? RRS feed

  • Question

  • I am slowly starting to understand how to use LINQ to SQL with ASP.NET, where I hae a separate layer that does the fethcing and saving of objects. One error that I got was that I could attach an object because it was already related to another context. Then I tried to use a data context in my service layer that has ObjectTrackingEnabled set to false for fetching objects. Now the error is gone, as long as I don't have concurrency or a version property I can simply get an object, change some fields and send it to the Save method.

    Here's why I'm confused: all the blogs say you need to serialize/deserialize a LINQ to SQL entity to effectively detach it. Others say that if DefferedLoading is off, that equals detached entities. None say that ObjectTrackingEnabled set to false will make entities detached, but that's what made the exception go away for me!

    I notice that with ObjectTrackingEnabled set to false, the entities have no handlers for PropertyChanging, I think that makes them 'detached', but because of a lack of evidence in the form of online discussions for this, I'm very confused, and worried I'm doing it wrong.

    Thanks for anyone who can clear this up for me!

    PS. Here's some code to show what I mean:

    Code Snippet

    using System;
    using System.Linq;

    public class ProductManager {
        private NorthwindDataContext context;

        public ProductManager() {
            context = new NorthwindDataContext();
            context.ObjectTrackingEnabled = false;
        }

        public Product Get(int id) {
            return context.Products.Single(p => p.ProductID == id);
        }

        public void Update(Product product) {
            using (NorthwindDataContext context = new NorthwindDataContext()) {
                // Get a detached original
                Product original = Get(product.ProductID);
                context.Products.Attach(product, original);
                context.SubmitChanges();
            }
        }
    }


    If I remove the secondline in the constructor I will get this error in the Update method upon attaching:

    An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext.  This is not supported.

    Saturday, May 17, 2008 6:55 PM

Answers

  • Hello,

     

    You are correct to assume that ObjectTrackingEnabled set to false means that entities returned from the query are not tracked. I believe this has, from the point of view of what you are trying to achieve, the same outcome as serializing the entity: you get entities that are not associated to any DataContext, so you can use them with Attach.

     

    Object Tracking is necessary for Deferred Loading, but not the other way around.

     

    Hope this helps.

    Diego

    Sunday, May 18, 2008 8:17 AM
  • Sidar,

    Hmmm... Actually, inside the Update method there is a Using block that declares a separate DataContext. Because it is using the same name ("context"), this one hides the one that is declared as a private class member.

    I also believe the original question is not about why this doesn't work when he removes the second line in the constructor, but to confirm how it *does* work when he doesn't remove it.

    But from your suggestions, I agree it would be safer to make the whole class IDisposable in case the private context is left in a state in which it holds some unmanaged resource.

    Hope this doesn’t make things more confusing,

    -Diego

    Sunday, May 18, 2008 6:15 PM

All replies

  • Hello,

     

    You are correct to assume that ObjectTrackingEnabled set to false means that entities returned from the query are not tracked. I believe this has, from the point of view of what you are trying to achieve, the same outcome as serializing the entity: you get entities that are not associated to any DataContext, so you can use them with Attach.

     

    Object Tracking is necessary for Deferred Loading, but not the other way around.

     

    Hope this helps.

    Diego

    Sunday, May 18, 2008 8:17 AM
  •  

    Hi Math,

     

    The problem is not the ObjectTrackingEnabled property, it is the code snippet. In the code snippet, you are not working in a detached mode, your context is still alive and when object tracking is enabled you are retrieving the object twice.Your Get methods returns an object that's already in the context, so reattaching it will cause the error you have sent - which is true.

     

    Try enabling object tracking, and instead of attaching it make some changes  in the variable named "original" and submit changes. You will see when you call submit changes for your context, the changes you have done to the original will ber reflected without executing that attach line.

     

    Going from one method to another neither kills the context nor disposes it, your context remains alive until you dispose the Context.

     

    Hope that explains it for you,

     

    Sidar

    Sunday, May 18, 2008 6:07 PM
  • Sidar,

    Hmmm... Actually, inside the Update method there is a Using block that declares a separate DataContext. Because it is using the same name ("context"), this one hides the one that is declared as a private class member.

    I also believe the original question is not about why this doesn't work when he removes the second line in the constructor, but to confirm how it *does* work when he doesn't remove it.

    But from your suggestions, I agree it would be safer to make the whole class IDisposable in case the private context is left in a state in which it holds some unmanaged resource.

    Hope this doesn’t make things more confusing,

    -Diego

    Sunday, May 18, 2008 6:15 PM
  • Ah - sorry I missed that line Sad you are right then I probably went down a totally different road Smile

     

    Then if I hopefully understood the situation,now the error text explains its self isn't it ?

     

    "An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext.  This is not supported"

     

    They are 2 seperate DataContexts and if one entity is attached to another context it is not supported to work with it - since it is still attached to that context.

     

    It works when he doesnt remove it, because then the "original"  entitiy is not tracked by another DataContext . (which is the global datacontext within the class in our case).

     

    Hope this didnt make thinkgs even more confusing Smile

     

    Sidar

     

     

    Sunday, May 18, 2008 6:37 PM
  • Nope, not confusing. Just wanted to clear this up, since I had a hard time finding definitve answer (most seem to focus on serializing).

    Thanks!
    Monday, May 19, 2008 9:12 PM