asp.net-mvc-3entity-frameworkobjectstatemanager

Object with same key already exists in objectstatemanager


Lots of questions about this error, and yet I cant figure out my problem (maybe i need some more of the theory around this).

I'm gettin the "Object with same key already exists in objectstatemanager" error and what im trying to do is so simple, I just have a Edit View for client, which has a list of Phones. As sson as the user hits the Save button, I just wrap everything with Json and send it to the controller with Ajax.

On the Controller, im supposed to check which phones on the list sent i should update, insert as news and delete.

So here's the important part of the code (and the one that throws the exeception mentioned):

            if (ModelState.IsValid)
            {
                foreach (var tel in propModel.Proprietario.Telefones)
                {
                    //Updates
                    TelefoneProprietario telToEdit = null;
                    if (tel.IDTelefoneProprietario.HasValue)
                        telToEdit = db.TelefonesProprietarios.Find(tel.IDTelefoneProprietario);
                    if (telToEdit != null)
                    {
                        db.Entry(tel).State = EntityState.Modified; << Exception HERE!!!
                    }
                    else
                    {
                        //Inserts
                        db.TelefonesProprietarios.Add(tel);
                    }
                }

                if (propModel.Proprietario.IDProprietario.HasValue)
                {
                    var prop = db.Proprietarios.Find(propModel.Proprietario.IDProprietario);
                    prop.LoadLists();
                    foreach (var telDel in prop.Telefones)
                    {
                        //Deletes
                        if (propModel.Proprietario.Telefones.Find(t => t.IDTelefoneProprietario == telDel.IDTelefoneProprietario) == null)
                        {
                            db.TelefonesProprietarios.Remove(telDel);
                        }
                    }
                }

                db.Entry(propModel.Proprietario).State = EntityState.Modified;
                db.SaveChanges();

                return Json(new { Success = 1, IDProprietario = propModel.Proprietario.IDProprietario, ex = "" });
            }

Any help or suggestions?

And to make it even worst: I took the line throwing the exception out, just to test the rest of the code, and on the last line before the SaveChanges, it throws another exception:

The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.

UPDATE:

I manage to solve part of the problem re-writing the routine above in another form, like this:

                if (prop.IDProprietario.HasValue)
                {
                    //Separete updates/inserts from deletes
                    List<int?> dbTels = db.TelefonesProprietarios
                                    .Where(dt => dt.IDProprietario == prop.IDProprietario)
                                    .Select(dt => dt.IDTelefoneProprietario)
                                    .ToList();

                    List<int?> postedTels = prop.Telefones
                        .Select(pt => pt.IDTelefoneProprietario)
                        .ToList();

                    List<int?> deletedTels = dbTels
                        .Except(postedTels).ToList();

                    //Perform deletes
                    foreach (var delTelId in deletedTels)
                    {
                        if (delTelId.HasValue)
                        {
                            TelefoneProprietario delTel = db.TelefonesProprietarios
                                .Where(dt => dt.IDProprietario == prop.IDProprietario && dt.IDTelefoneProprietario == delTelId)
                                .Single();

                            db.Entry(delTel).State = EntityState.Deleted;
                        }
                    }

                    //Perform insert and updates
                    foreach (var tel in prop.Telefones)
                    {
                        if (tel.IDTelefoneProprietario.HasValue)
                        {
                            db.Entry(tel).State = EntityState.Modified;
                        }
                        else
                        {
                            db.Entry(tel).State = EntityState.Added;
                            tel.IDProprietario = (int)prop.IDProprietario;
                        }
                    }

                    db.Entry(prop).State = EntityState.Modified;
                }
                else 
                {
                    db.Proprietarios.Add(prop);
                }
                db.SaveChanges();

Only problem left now is for deleting a Proprietario instance (cause it has a List of TelefoneProprietario and the TelefoneProprietario has a reference back to the Proprietario that ownes it. This cenario causes a "relationship between the two objects cannot be defined because they are attached to different ObjectContext objects" as widely discussed here in SO... Trying to figure out a solution, so if you can point me something...)


Solution

  • When you do this: db.Entry(tel).State = EntityState.Modified;

    tel object is just a object model you pass in, right?

    So EF context at this time does not keep track of any object which has the same key with tel's key in this case IDTelefoneProprietario

    Therefore if you set the object state to Modified then SaveChanges() EF will throw error.

    Do this instead:

    if (telToEdit != null)
    {
        // Do apply all the changes from 'tel' to 'telToEdit' object here
        ...
        db.Entry(telToEdit).State = EntityState.Modified; // No Exception I hope :)
    }
    

    Hope it makes sense.