views:

232

answers:

2

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();
        }
+3  A: 

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.

Philip Daubmeier
The code I posted was just a simplification. I need to be able to retrieve a Member from the db and then process it in detached mode. Then somewhere else a while later update that Member in the db. I can't do it all in the same datacontext.
remdao
That wont work, you have to stay in the same context, meaning you have to perform the attach and submitchanges operations on the same instance of TheDataContext from which you retrieved the object.
Philip Daubmeier
updated again :)
Philip Daubmeier
Was this what you were looking for? Sure, it isnt a very elegant solution, but you just cant switch contexts. Another way would be to just hold the datacontext in a static variable until the last submitchanges call.
Philip Daubmeier
Yes this is the approach I've been using before. But it seems kinda unnecessary to have to do a select before each update. So that's why I've been trying to use Attach instead. But I don't quite understand why Microsoft added this method at all since it's usability seem very limited.
remdao
Updated my answer one more time. The problem could be the references, still stored in the object. If my last solution works, you could leave deferred loading turned on.
Philip Daubmeier
@'But I don't quite understand why Microsoft added this method': Because of providing the ability of updating the db with information gathered from deserialized objects.
Philip Daubmeier
A: 

It is possible to attach entities from another datacontext.

The only thing that needs to be added to code in the first post is this:

dc.DeferredLoadingEnabled = false

But this is a drawback since deferred loading is very useful. I read somewhere on this page that another solution would be to set the Update Check on all properties to Never. This text says the same: http://complexitykills.blogspot.com/2008/03/disconnected-linq-to-sql-tips-part-1.html

But I can't get it to work even after setting the Update Check to Never.

remdao