0

So I am trying to Delete some items from the database before I Insert some data. For some reason, C# Entity Framework and ASP.NET do not enjoy me doing this simple operation and gives out another one of those vague errors.

I am trying to update a set of rows of information in a table (using foreach loops and Insert/Delete), as well as some properties in another table (using update)

How do I fix it? The error occurs on the Delete function, on the line: this.entities.tableModule.Attach(module);

I get: "System.InvalidOperationException: An entity object cannot be referenced by multiple instances of IEntityChangeTracker."

public void Insert(tableModule module)
    {
        this.entities.tableModule.AddObject(module);
        this.entities.SaveChanges();
    }    
public void Delete(tableModule module)
    {
        this.entities.tableModule.Attach(module); // error HERE
        this.entities.DeleteObject(module);
        this.entities.SaveChanges();
    }

Further down the code I call Delete and Insert and Update for another table.

try
        {
            DifferentClass.Update(tu);
            foreach (tableModule mitem in list_to_del)
            {
                moduleclass.Delete(mitem); // remove all super roles by the user.
            }
            foreach (tableModule m_to_add in add_list)
            {
                moduleclass.Insert(m_to_add);
            }
        }

From what I gather, the attach function is maybe being run more than once and that for some reason is something that the designers of C# Entity Framework are completely caught by surprise for, and so they produce an error. Though it's most likely my complete lack of understanding of entity framework.

EDIT: Here's how I get the list_to_del array.

List<tableModule> list_to_del = (from m in entities.tableModule where m.userid == (long)userID select m).ToList(); 

EDIT2:

New test code:

public void InsertQueue(tableModule module)
{
    this.entities.tableModule.AddObject(module);
}
public void DeleteQueue(tableModule module)
{
    this.entities.tableModule.Attach(module);
    this.entities.DeleteObject(module);
}
public void FinallySave(){
    this.entities.SaveChanges();
}

EDIT 3 ---- SOLUTION -----

The test code worked sort of (though inserts didn't for some odd reason). The problem was, I was calling list_to_del query to get that array of tableModules from a tableUser class which has its own entityset/context. So the results in list_to_del were of a different context, than the call to the class that does DeleteQueue / Insert etc.

I changed:

List<tableModule> list_to_del = (from m in entities.tableModule where m.userid == (long)userID select m).ToList(); 

to the appropriate class that has the SAME query:

List<tableModule> list_to_del = ModuleClass.GetListofModulesByUserID(userID);

Of course ModuleClass.InsertQueue and ModuleClass.DeleteQueue is called.

So everything uses the same entities object (context/entityset).

So the error happens when you call a query on a context, that returns a set of results that are ALREADY attached to that context. Then when you call Attach again, a problem occurs because they already are in a context on some other class/instance.

3
  • Your list_to_del could contain dupes or entities loaded from a context and not properly detached. Commented Dec 13, 2011 at 15:29
  • Isn't there a way to do some sort of check in Delete, like if(!AlreadyAttached)Attach ?? Commented Dec 13, 2011 at 15:32
  • List<tableModule> list_to_del = (from m in entities.tableModule where m.userid == (long)userID select m).ToList(); // Thats how I get list_to_del Commented Dec 13, 2011 at 15:34

1 Answer 1

2

You don't need to call Attach if you loaded module from the same context instance - you can call DeleteObject directly. When you load entity from the context it is by default tracked by the context (= it is attached) and you cannot attach it again. You also cannot attach it to different context so make sure that list_to_del is loaded by the same context instance as you use for deletion (= it must be loaded in the same request processing because you should have a new context instance per request).

Sign up to request clarification or add additional context in comments.

21 Comments

I don't know if I am going about this the right way, I really don't fully understand the need of attachments and contexts. But what if I made a function called InsertQueue and DeleteQueue which will simply call entities.AddObject() and DeleteObject(), and then FinallySave() which will call entities.SaveChanges()? Would that work better? I tried the following in the next comment, but now it says objects are not in object state manager.
Don't put the code in comments. It is unreadable. Modify your question if you need to pass another code. Also follow your initial naming. It is confusing if you start question with some example and you follow with different one. Read my answer again and think about the main points: usage of the context, source of list_to_del, relations between entities.
Yes there we go. I added it with correct naming onto EDIT2. I was trying it on different test page, so hence the problems with that code. Your answer is simply not clear. How do I know if it will be loaded in the same context or not. It's simply loaded in a very standard way. How would I know if the same request processing is used or if a new context instance is used per request? I don't do anything to deal with contexts at all. There's no reason for me to use contexts when I just want to insert and delete items from a database. I didn't attach somewhere before, so situation here is impossible
I've seen all the related questions about this topic, and even your own responses before. The answer is simply not clear. There should be a very SIMPLE answer to this, like if(!Object.AlreadyAttached()){AttachObject }else { ClearAttachments(); }
How do I know if it will be loaded in the same context or not. You know it because you write the code = you know how do you instantiate the context and how do you use it. How would I know if the same request processing is used or if a new context instance is used per request? Again you know it because you write the code. If you don't know if the code is executed in the same request processing as data loading then you have much bigger problem and you should start learning ASP.NET from the beginning.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.