C# entity对象不能被多个IEntityChangeTracker实例引用。在实体框架4.1中将相关对象添加到实体时
我正在尝试保存员工详细信息,其中包含与City的引用。但每次我尝试保存联系人时(经过验证),我都会遇到异常“ADO.Net实体框架一个实体对象不能被多个EntityChangeTracker实例引用” 我读了这么多的帖子,但还是不知道该怎么办。。。 下面给出了我的保存按钮点击代码C# entity对象不能被多个IEntityChangeTracker实例引用。在实体框架4.1中将相关对象添加到实体时,c#,asp.net,entity-framework,ado.net,foreign-keys,C#,Asp.net,Entity Framework,Ado.net,Foreign Keys,我正在尝试保存员工详细信息,其中包含与City的引用。但每次我尝试保存联系人时(经过验证),我都会遇到异常“ADO.Net实体框架一个实体对象不能被多个EntityChangeTracker实例引用” 我读了这么多的帖子,但还是不知道该怎么办。。。 下面给出了我的保存按钮点击代码 protected void Button1_Click(object sender, EventArgs e) { EmployeeService es = new EmployeeServi
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();
。。。不要在构造函数中使用参数,我想您应该在类中创建一个上下文。当您加载城市1
Payroll.Entities.City city1 = cs.SelectCity(...);
…将city1
附加到CityService
中的上下文。稍后,您将添加一个city1
作为对新员工e1
的引用,并将e1
包括对city1
的引用添加到EmployeeService
的上下文中。因此,您将city1
附加到两个不同的上下文,这正是异常所抱怨的
您可以通过在服务类之外创建上下文并在两个服务中注入和使用上下文来解决此问题:
EmployeeService es = new EmployeeService(context);
CityService cs = new CityService(context); // same context instance
您的服务类看起来有点像只负责单一实体类型的存储库。在这种情况下,当您为服务使用单独的上下文时,一旦涉及实体之间的关系,您就会遇到麻烦
您还可以创建一个服务,该服务负责一组密切相关的实体,如EmployeeCityService
(具有单个上下文),并将按钮1\u Click
方法中的整个操作委托给该服务的一个方法。我也有同样的问题,但我对@Slauma的解决方案有问题(虽然在某些情况下很好)是它建议我将上下文传递到服务中,这意味着上下文可以从我的控制器获得。它还强制我的控制器和服务层之间的紧密耦合
我使用依赖项注入将服务/存储库层注入控制器,因此无法从控制器访问上下文
我的解决方案是让服务/存储库层使用相同的上下文实例-单例
上下文单例类:
参考资料:
及
公共密封类MyModelDbContextSingleton
{
私有静态只读MyModelDbContext实例=新建MyModelDbContext();
静态MyModelDbContextSingleton(){}
私有MyModelDbContextSingleton(){}
公共静态MyModelDbContext实例
{
得到
{
返回实例;
}
}
}
存储库类:
公共类项目存储库:IProjectRepository
{
MyModelDbContext上下文=MyModelDbContextSingleton.Instance;
[...]
其他解决方案确实存在,比如实例化一次上下文并将其传递给服务/存储库层的构造函数,或者我读到的另一个实现工作单元模式的解决方案。我确信还有更多…我遇到了同样的问题,我可以解决创建我试图更新的对象的新实例的问题。然后我将该对象传递给我的repostory。这是一个旧线程,但我更喜欢的另一个解决方案是只更新cityId,而不将孔模型City分配给Employee…要执行此操作,Employee应该如下所示:
公共类员工{
...
public int?CityId;//表示允许城市为空
公共虚拟城市;
}
那就足够了:
e1.CityId=city1.ID;
复制步骤可以简化为:
var contextOne=new EntityContext();
var contextTwo=新的EntityContext();
var user=contextOne.Users.FirstOrDefault();
var group=新组();
group.User=User;
contextTwo.Groups.Add(组);
contextTwo.SaveChanges();
无错误代码:
var context=new EntityContext();
var user=context.Users.FirstOrDefault();
var group=新组();
group.User=User;//设置实体属性时要小心。
//确保所有对象都来自同一上下文
context.Groups.Add(组);
SaveChanges();
仅使用一个EntityContext
可以解决此问题。有关其他解决方案,请参阅其他答案。除了注入和更糟糕的单例,您可以在添加之前调用分离方法
EntityFramework 6:((IObjectContextAdapter)cs.ObjectContext.Detach(city1);
EntityFramework 4:cs.Detach(城市1);
如果不需要第一个DBContext对象,还有另一种方法。只需使用关键字将其用包装即可:
Payroll.Entities.City city1;
using (CityService cs = new CityService())
{
city1 = cs.SelectCity(Convert.ToInt64(cmbCity.SelectedItem.Value));
}
在我的例子中,我使用的是ASP.NET Identity Framework。我使用内置的UserManager.FindBynameSync
方法检索ApplicationUser
实体。然后我尝试在另一个DbContext
上的新创建实体上引用该实体。这导致了您最初看到的异常
我通过从UserManager
方法创建一个新的ApplicationUser
实体,仅使用Id
,并引用该新实体来解决此问题。错误源:
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
希望有人能节省一些宝贵的时间在整个事务中使用相同的DBContext对象。在这种情况下,错误很明显:Entity Framework无法使用多个IEntityChangeTracker
实例或多个DBContext
实例跟踪实体。解决方案是:使用DbContext
的一个实例;通过单个存储库访问所有需要的实体(取决于DbContext
的一个实例);或关闭跟踪
private readonly IMyEntityRepository myEntityRepo; // depends on MyDbContext
private readonly IFooRepository fooRepo; // depends on MyDbContext
private readonly IBarRepository barRepo; // depends on MyDbContext
public MyController(
IMyEntityRepository myEntityRepo,
IFooRepository fooRepo,
IBarRepository barRepo)
{
this.fooRepo = fooRepo;
this.barRepo = barRepo;
this.myEntityRepo = myEntityRepo;
}
...
myEntity.Foo = await this.fooRepository.GetFoos().SingleOrDefaultAsync(f => f.Id == model.FooId);
if (model.BarId.HasValue)
{
myEntity.Foo.Bar = await this.barRepository.GetBars().SingleOrDefaultAsync(b => b.Id == model.BarId.Value);
}
...
await this.myEntityRepo.UpdateAsync(myEntity); // this throws an error!
// services.AddTransient<DbContext, MyDbContext>(); <- one instance per ctor. bad
services.AddScoped<DbContext, MyDbContext>(); // <- one instance per call. good!
myEntity.Foo.Bar = await this.barRepo.GetBars().AsNoTracking().SingleOrDefault(b => b.Id == model.BarId);
ApplicationUser user = new ApplicationUser();
user = UserManager.FindById(User.Identity.GetUserId());
Order entOrder = new Order();
entOrder.ApplicationUser = user; //I need this user before saving to my database using EF
ApplicationDbContext db = new ApplicationDbContext();
db.Entry(entOrder).State = EntityState.Added;
db.SaveChanges();
user = UserManager.FindById(User.Identity.GetUserId());
//db instance here is the same instance as my db on my code above.
user = db.Users.Find(User.Identity.GetUserId());