c# - Entidad marco de ADO.Net Un objeto de entidad no puede ser referenciado por varias instancias de IEntityChangeTracker
entity-framework (3)
He visto esto antes, es posible que tenga que convertir el campo de Referencia en un EntityKey antes de guardar y luego cargarlo después de guardarlo. Pruebe este código en su lugar:
public Contact CreateContact(Contact contact){
contact.ConvertContactRelationToReference();
_entities.AddToContact(contact);
//throws the exception
_entities.SaveChanges();
contact.ContactRelation.Load();
return contact;
}
public partial class Contact
{
public void ConvertContactRelationToReference()
{
var crId = ContactRelation.Id;
ContactRelation = null;
ContactRelationReference.EntityKey = new EntityKey("MyEntities.ContactRelations", "Id", crId);
}
}
Por supuesto, es posible que deba cambiar parte de este código dependiendo de la estructura exacta de su base de datos.
Estoy intentando guardar mi contacto, que tiene referencias a la Relación de contacto (solo la relación del contacto, casado, soltero, etc.) y el país. Pero cada vez que trato de guardar mi contacto, que está validado, obtengo la excepción "Entorno de Entidad ADO.Net. Un objeto de entidad no puede ser referenciado por varias instancias de IEntityChangeTracker"
public Contact CreateContact(Contact contact)
{
_entities.AddToContact(contact); //throws the exception
_entities.SaveChanges();
return contact ;
}
Estoy usando un diseño de MVC acoplado a Servicios y Repositorios. He leído muchas publicaciones sobre esta excepción, pero ninguna me da una respuesta práctica ...
Gracias Pedro
Ummm me pregunto si alguien puede, por favor, cordura comprobar mi solución. Es muy similar a la respuesta aceptada a continuación, pero después de leer el blog de Rick Strahl sobre DataContext Life Management , me preocupa que esta no sea una solución segura para subprocesos para una aplicación web.
También resolví la instancia en la que recibía este mensaje de error al acceder al contexto de mi objeto utilizando el patrón de singleton.
Agregué lo siguiente a la clase MyObjectContext:
// singleton
private static MyObjectContext context;
public static MyObjectContext getInstance()
{
if (context == null)
{
context = new MyObjectContext ();
}
return context;
}
Y en mi asignador de repositorio por entidad en lugar de crear una instancia de una nueva instancia de MyObjectContext que uso
var db = MyObjectContext.getInstance();
¿Estoy siendo estúpido aquí? Parece funcionar.
[Actualizar]
Como se utiliza L2E, primero debe guardar todos los objetos vinculados antes de poder guardar el objeto principal. Lo que tiene sentido, de lo contrario, crearía (en mi ejemplo) un artista sin su objeto de contacto. Esto no está permitido por el diseño de la base de datos.
[/Actualizar]
Aquí está mi implementación que funcionó.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Artist artist, [Bind(Prefix = "Contact")] Contact contact, [Bind(Prefix = "Country")] Country country, [Bind(Prefix = "ContactRelationship")] ContactRelationship contactRelationship)
{
ViewData["Countries"] = new SelectList(new CountryService(_msw).ListCountries().OrderBy(c => c.Name), "ID", "Name");
ViewData["ContactRelationships"] = new SelectList(new ContactRelationshipService(_msw).ListContactRelationships().OrderBy(c => c.ID), "ID", "Description");
country = _countryService.GetCountryById(country.ID);
contact.Country = country;
contactRelationship = _contactRelationshipService.GetContactRelationship(contactRelationship.ID);
contact.ContactRelationship = contactRelationship;
if(_contactService.CreateContact(contact)){
artist.Contact = contact;
if (_service.CreateArtist(artist))
return RedirectToAction("Index");
}
return View("Create");
}
Y luego en mi ContactRepository:
public Contact CreateContact(Contact contact)
{
_entities.AddToContact(contact); //no longer throws the exception
_entities.SaveChanges();
return contact ;
}
También encontré en este sitio web que es mejor mantener el mismo contexto en toda la aplicación, así que ahora estoy usando una clase de datos especial para esto:
Rick Strahl y Samuel Maecham me han enseñado que debe mantener su contexto de datos por usuario por solicitud. Lo que significa ponerlo en el HttpContext para aplicaciones web. Lea todo sobre esto here
public class Data
{
public static MyDBEntities MyDBEntities
{
get
{
if (HttpContext.Current != null && HttpContext.Current["myDBEntities"] == null)
{
HttpContext.Current["myDBEntities"] = new MyDBEntities ();
}
return HttpContext.Current["myDBEntities"] as MyDBEntities;
}
set {
if(HttpContext.Current != null)
HttpContext.Current["myDBEntities"] = value;
}
}
}