Search code examples
sqllinqsql-update

LINQ SQL Attach, Update Check set to Never, but still Concurrency conflicts


In the dbml designer I've set Update Check to Never on all properties. But i still get an exception when doing Attach: "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." This approach seems to have worked for others on here, but there must be something I've missed.

        using(TheDataContext dc = new TheDataContext())
        {
            test = dc.Members.FirstOrDefault(m => m.fltId == 1);
        }

        test.Name = "test2";

        using(TheDataContext dc = new TheDataContext())
        {
            dc.Members.Attach(test, true);
            dc.SubmitChanges();
        }

Solution

  • The error message says exactly what is going wrong: You are trying to attach an object that has been loaded from another DataContext, in your case from another instance of the DataContext. Dont dispose your DataContext (at the end of the using statement it gets disposed) before you change values and submit the changes. This should work (all in one using statement). I just saw you want to attach the object again to the members collection, but it is already in there. No need to do that, this should work just as well:

    using(TheDataContext dc = new TheDataContext())
    {
        var test = dc.Members.FirstOrDefault(m => m.fltId == 1);
        test.Name = "test2";
        dc.SubmitChanges();
    }
    

    Just change the value and submit the changes.

    Latest Update:

    (Removed all previous 3 updates)

    My previous solution (removed it again from this post), found here is dangerous. I just read this on a MSDN article:

    "Only call the Attach methods on new or deserialized entities. The only way for an entity to be detached from its original data context is for it to be serialized. If you try to attach an undetached entity to a new data context, and that entity still has deferred loaders from its previous data context, LINQ to SQL will thrown an exception. An entity with deferred loaders from two different data contexts could cause unwanted results when you perform insert, update, and delete operations on that entity. For more information about deferred loaders, see Deferred versus Immediate Loading (LINQ to SQL)."

    Use this instead:

    // Get the object the first time by some id
    using(TheDataContext dc = new TheDataContext())
    {
        test = dc.Members.FirstOrDefault(m => m.fltId == 1);
    }
    
    // Somewhere else in the program
    test.Name = "test2";
    
    // Again somewhere else
    using(TheDataContext dc = new TheDataContext())
    {
        // Get the db row with the id of the 'test' object
        Member modifiedMember = new Member()
        {
            Id = test.Id,
            Name = test.Name,
            Field2 = test.Field2,
            Field3 = test.Field3,
            Field4 = test.Field4
        };
        
        dc.Members.Attach(modifiedMember, true);
        dc.SubmitChanges();
    }
    

    After having copied the object, all references are detached, and all event handlers (deferred loading from db) are not connected to the new object. Just the value fields are copied to the new object, that can now be savely attached to the members table. Additionally you do not have to query the db for a second time with this solution.