objeto de entidad no puede ser referenciado por varias instancias de IEntityChangeTracker. al agregar objetos relacionados a la entidad en Entity Framework 4.1

Estoy tratando de guardar los detalles del empleado, que tiene referencias con City. Pero cada vez que trato de guardar mi contacto, que está validado, obtengo la excepción “ADO.Net Entity Framework. Un objeto de entidad no puede ser referenciado por múltiples instancias de IEntityChangeTracker”

Había leído tantas publicaciones pero aún no obtenía la idea exacta de qué hacer … mi código de clic para guardar está a continuación.

protected void Button1_Click(object sender, EventArgs e) { EmployeeService es = new EmployeeService(); CityService cs = new CityService(); DateTime dt = new DateTime(2008, 12, 12); Payroll.Entities.Employee e1 = new Payroll.Entities.Employee(); Payroll.Entities.City city1 = cs.SelectCity(Convert.ToInt64(cmbCity.SelectedItem.Value)); e1.Name = "Archana"; e1.Title = "aaaa"; e1.BirthDate = dt; e1.Gender = "F"; e1.HireDate = dt; e1.MaritalStatus = "M"; e1.City = city1; es.AddEmpoyee(e1,city1); } 

y el código de servicio del empleado

 public string AddEmpoyee(Payroll.Entities.Employee e1, Payroll.Entities.City c1) { Payroll_DAO1 payrollDAO = new Payroll_DAO1(); payrollDAO.AddToEmployee(e1); //Here I am getting Error.. payrollDAO.SaveChanges(); return "SUCCESS"; } 

Porque estas dos líneas …

 EmployeeService es = new EmployeeService(); CityService cs = new CityService(); 

… no tome un parámetro en el constructor, supongo que crea un contexto dentro de las clases. Cuando cargas la city1

 Payroll.Entities.City city1 = cs.SelectCity(...); 

… adjunta la city1 al contexto en CityService . Más tarde, agrega una city1 como referencia al nuevo Employee e1 y agrega e1 incluida esta referencia a city1 al contexto en EmployeeService . Como resultado, tiene city1 adjuntado a dos contextos diferentes, de lo que se queja la excepción.

Puede solucionar esto creando un contexto fuera de las clases de servicio e inyectándolo y utilizándolo en ambos servicios:

 EmployeeService es = new EmployeeService(context); CityService cs = new CityService(context); // same context instance 

Sus clases de servicio se parecen un poco a los repositorys que son responsables de un solo tipo de entidad. En tal caso, siempre tendrá problemas tan pronto como las relaciones entre entidades estén involucradas cuando use contextos separados para los servicios.

También puede crear un único servicio que sea responsable de un conjunto de entidades estrechamente relacionadas, como EmployeeCityService (que tiene un único contexto) y delegue toda la operación en su método Button1_Click a un método de este servicio.

Los pasos para reproducir se pueden simplificar a esto:

 var contextOne = new EntityContext(); var contextTwo = new EntityContext(); var user = contexOne.Users.FirstOrDefault(); var group = new Group(); group.User = user; contextTwo.Groups.Add(group); contextTwo.SaveChanges(); 

Código sin error:

 var context = new EntityContext(); var user = context.Users.FirstOrDefault(); var group = new Group(); group.User = user; // Be careful when you set entity properties. // Be sure that all objects came from the same context context.Groups.Add(group); context.SaveChanges(); 

Este es un hilo antiguo, pero otra solución, que prefiero, es simplemente actualizar cityId y no asignar el modelo de agujero City a Employee … para que el empleado se vea así:

 public class Employee{ ... public int? CityId; //The ? is for allow City nullable public virtual City City; } 

Entonces es suficiente asignar:

 e1.CityId=city1.ID; 

Tuve el mismo problema pero mi problema con la solución de @Sumauma (aunque excelente en ciertos casos) es que recomienda pasar el contexto al servicio, lo que implica que el contexto está disponible desde mi controlador. También fuerza un fuerte acoplamiento entre mi controlador y las capas de servicio.

Estoy usando Dependency Injection para inyectar las capas de servicio / repository en el controlador y, como tal, no tengo acceso al contexto desde el controlador.

Mi solución fue hacer que las capas de servicio / repository usaran la misma instancia del contexto: Singleton.

Contexto Singleton Class:

Referencia: http://msdn.microsoft.com/en-us/library/ff650316.aspx
y http://csharpindepth.com/Articles/General/Singleton.aspx

 public sealed class MyModelDbContextSingleton { private static readonly MyModelDbContext instance = new MyModelDbContext(); static MyModelDbContextSingleton() { } private MyModelDbContextSingleton() { } public static MyModelDbContext Instance { get { return instance; } } } 

Clase de repository:

 public class ProjectRepository : IProjectRepository { MyModelDbContext context = MyModelDbContextSingleton.Instance; 

Existen otras soluciones, como instanciar el contexto una vez y pasarlo a los constructores de las capas de servicio / repository u otro sobre el cual estoy implementando el patrón Unidad de trabajo. Estoy seguro de que hay más …

Alternativamente a la inyección y aún peor Singleton, puede llamar al método Detach antes de Agregar.

EntityFramework 6: ((IObjectContextAdapter)cs).ObjectContext.Detach(city1);

EntityFramework 4: cs.Detach(city1);

Hay otra manera, en caso de que no necesite el primer objeto DBContext. Simplemente envuélvelo con la palabra clave:

 Payroll.Entities.City city1; using (CityService cs = new CityService()) { city1 = cs.SelectCity(Convert.ToInt64(cmbCity.SelectedItem.Value)); } 

En mi caso, estaba usando el Marco de Identidad ASP.NET. UserManager.FindByNameAsync método integrado UserManager.FindByNameAsync para recuperar una entidad ApplicationUser . Luego intenté hacer referencia a esta entidad en una entidad recién creada en un DbContext diferente. Esto resultó en la excepción que originalmente viste.

Lo resolví creando una nueva entidad ApplicationUser con solo el Id del método UserManager y haciendo referencia a esa nueva entidad.

Tuve el mismo problema y pude resolver la creación de una nueva instancia del objeto que intentaba actualizar. Luego pasé ese objeto a mi repository.

Use el mismo objeto DBContext a lo largo de la transacción.

Fuente de error:

 ApplicationUser user = await UserManager.FindByIdAsync(User.Identity.Name); ApplicationDbContext db = new ApplicationDbContent(); db.Users.Uploads.Add(new MyUpload{FileName="newfile.png"}); await db.SavechangesAsync();/ZZZZZZZ 

Espero que alguien ahorre un tiempo precioso