实体对象不能被IEntityChangeTracker的多个实例引用。 同时在entity framework4.1中添加相关对象到实体
我正在尝试保存员工详细信息,该信息与城市有关。 但每次我尝试保存我的联系人,这是validation我得到exception“ADO.Netentity framework一个实体对象不能被多个IEntityChangeTracker实例引用”
我读过这么多的post,但仍然没有得到确切的想法做什么…我保存button点击代码如下
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); }
和员工服务代码
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"; }
因为这两条线
EmployeeService es = new EmployeeService(); CityService cs = new CityService();
…不要在构造函数中使用参数,我想你会在类中创build一个上下文。 当你加载city1
…
Payroll.Entities.City city1 = cs.SelectCity(...);
…将city1
附加到city1
中的上下文。 稍后,将city1
添加为新Employee
e1
的引用,并将包括对city1
此引用的 e1
添加到city1
中的上下文中。 结果你有city1
附加到两个不同的上下文,这是exception抱怨。
您可以通过在服务类之外创build一个上下文来解决这个问题,并在两个服务中注入和使用它:
EmployeeService es = new EmployeeService(context); CityService cs = new CityService(context); // same context instance
你的服务类看起来有点像只负责一个实体types的仓库。 在这种情况下,如果在为服务使用单独的上下文时,只要涉及到实体之间的关系,就总是会遇到麻烦。
您还可以创build一个服务,负责一组紧密相关的实体,如EmployeeCityService
(具有单个上下文),并将Button1_Click
方法中的整个操作委托给此服务的一个方法。
重现步骤可以简化为:
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();
代码没有错误:
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();
我有同样的问题,但我的问题与@ Slauma的解决scheme(虽然在某些情况下很好)是,它build议我将上下文传递到服务,这意味着上下文可从我的控制器。 它也强制我的控制器和服务层之间的紧密耦合。
我使用dependency injection来将服务/存储库层注入到控制器中,因此无法访问控制器的上下文。
我的解决scheme是让服务/存储库层使用相同的上下文实例 – 单例。
上下文Singleton类:
参考: http : //msdn.microsoft.com/en-us/library/ff650316.aspx
和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; } } }
存储库类:
public class ProjectRepository : IProjectRepository { MyModelDbContext context = MyModelDbContextSingleton.Instance;
其他解决scheme确实存在,例如一次实例化上下文,并将其传递到服务/存储库层的构造函数中,或者另一种解决scheme是读取有关实现“工作单元”模式的信息。 我相信还有更多…
另外注射,甚至更糟糕的单身人士,你可以调用分离方法之前添加。
EntityFramework 6 : ((IObjectContextAdapter)cs).ObjectContext.Detach(city1);
EntityFramework 4: cs.Detach(city1);
还有另一种方法,如果你不需要第一个DBContext对象。 只需使用关键字包装它:
Payroll.Entities.City city1; using (CityService cs = new CityService()) { city1 = cs.SelectCity(Convert.ToInt64(cmbCity.SelectedItem.Value)); }
这是一个古老的线程,但我更喜欢的另一个解决scheme是更新cityId,而不是将空洞模型City分配给Employee …要这样做Employee应该看起来像:
public class Employee{ ... public int? CityId; //The ? is for allow City nullable public virtual City City; }
那么分配就足够了:
e1.CityId=city1.ID;
在我的情况下,我正在使用ASP.NET身份框架。 我曾经使用内置的UserManager.FindByNameAsync
方法来检索一个ApplicationUser
实体。 然后我尝试在不同的DbContext
上新创build的实体上引用此实体。 这导致你原来看到的例外。
我通过创build一个新的ApplicationUser
实体来解决这个问题,只需要使用UserManager
方法中的Id
并引用新的实体。
我有同样的问题,我可以解决我想要更新的对象的新实例。 然后我把这个东西传给了我的回报。
在整个事务中使用相同的DBContext对象。
错误来源:
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
希望有人节省一些宝贵的时间