Reputation: 447
I have an ASP.NET WebForms project with N-Layers using Entity Framework 5. I have two entities: Cliente and Banda. One Cliente may have many Banda's, and one Banda may have many Cliente's
In the bussines layer I have this code:
public void Update(Cliente cliente)
{
using (MegaStudioEntities contexto = new MegaStudioEntities())
{
if (contexto.Entry(cliente).State == EntityState.Detached)
contexto.Entry(cliente).State = EntityState.Modified;
//Delete existing relations
var qBandas = from qb in contexto.Bandas.Where(b => b.Clientes.Any(c => c.IdCliente == cliente.IdCliente))
select qb;
foreach (Banda b in qBandas.ToList())
((IObjectContextAdapter)contexto).ObjectContext.ObjectStateManager.ChangeRelationshipState(cliente, b, c => c.Bandas, EntityState.Deleted);
contexto.SaveChanges();
//Adding new relations
foreach (Banda banda in cliente.Bandas)
{
contexto.Bandas.Attach(banda);
((IObjectContextAdapter)contexto).ObjectContext.ObjectStateManager.ChangeRelationshipState(cliente, banda, c => c.Bandas, EntityState.Added);
}
cliente.TipoCliente = contexto.TipoClientes.Find(cliente.IdTipoCliente);
cliente.FechaModificacion = System.DateTime.Now;
Encriptar(cliente);
contexto.SaveChanges();
}
}
The first time I call Update method, run sucessfully, but the second time I get this error:
"An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key."
What I forget to close? This is the correct way to update many to many relations in EF5?
Thanks in advance!!!
Martin
UPDATE 1:
Finally my code is like that:
public void Update(Cliente cliente)
{
using (MegaStudioEntities contexto = new MegaStudioEntities())
{
Cliente savedClient = contexto.Clientes.Find(cliente.IdCliente);
foreach (var banda in savedClient.Bandas.ToList())
{
savedClient.Bandas.Remove(contexto.Bandas.Find(banda.IdBanda));
}
foreach (var banda in cliente.Bandas)
{
savedClient.Bandas.Add(contexto.Bandas.Find(banda.IdBanda));
}
contexto.Entry(savedClient).CurrentValues.SetValues(cliente);
contexto.SaveChanges();
}
}
Thanks Gert Arnold!!!
Upvotes: 4
Views: 919
Reputation: 109255
You don't really have to attach any object to the context. So you can prevent this exception by not doing that.
public void Update(Cliente cliente)
{
using (MegaStudioEntities contexto = new MegaStudioEntities())
{
Cliente savedClient = contexto.TipoClientes.Find(cliente.IdCliente);
foreach (var banda in savedClient.Bandas.ToList())
{
savedClient.Bandas.Remove(banda);
}
foreach (var banda in cliente.Bandas)
{
savedClient.Bandas.Add(banda);
}
savedClient.IdTipoCliente = cliente.IdTipoCliente;
savedClient.FechaModificacion = System.DateTime.Now;
Encriptar(cliente);
contexto.SaveChanges();
}
}
I'm not sure if this break code in Encriptar(cliente);
because (obviously) I don't know what happens there.
As you see, you add and remove associations in a m:m relationship by adding/removing objects. You hardly ever (probably never) need to manipulate relationship state explicitly. If you feel a need to do that it most likely indicates that you overlook an easier way to achieve what you want.
Upvotes: 4