简体   繁体   English

实体对象不能被 IEntityChangeTracker 的多个实例引用。 在 Entity Framework 4.1 中向实体添加相关对象时

[英]entity object cannot be referenced by multiple instances of IEntityChangeTracker. while adding related objects to entity in Entity Framework 4.1

I am trying to save Employee details, which has references with City.我正在尝试保存 Employee 详细信息,该详细信息与 City 相关。 But everytime I try to save my contact, which is validated I get the exception "ADO.Net Entity Framework An entity object cannot be referenced by multiple instances of IEntityChangeTracker"但是每次我尝试保存已验证的联系人时,我都会收到异常“ADO.Net 实体框架实体对象不能被 IEntityChangeTracker 的多个实例引用”

I had read so many post but still not getting the exact idea of what to do... my Save button click code is given below我已经阅读了很多帖子,但仍然不知道该怎么做……我的保存按钮点击代码如下

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);
    }

and Employeeservice Code员工服务代码

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";
        }

Because these two lines ...因为这两行...

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

... don't take a parameter in the constructor, I guess that you create a context within the classes. ...不要在构造函数中使用参数,我猜您在类中创建了一个上下文。 When you load the city1 ...当你加载city1 ...

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

...you attach the city1 to the context in CityService . ...您附加city1在上下文CityService Later you add a city1 as a reference to the new Employee e1 and add e1 including this reference to city1 to the context in EmployeeService .后来你添加一个city1作为新的参考Employee e1 ,并添加e1包括这个参考city1在语境中EmployeeService As a result you have city1 attached to two different context which is what the exception complains about.因此,您将city1附加到两个不同的上下文,这是异常所抱怨的。

You can fix this by creating a context outside of the service classes and injecting and using it in both services:您可以通过在服务类之外创建上下文并在两个服务中注入和使用它来解决此问题:

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

Your service classes look a bit like repositories which are responsible for only a single entity type.您的服务类看起来有点像只负责单一实体类型的存储库。 In such a case you will always have trouble as soon as relationships between entities are involved when you use separate contexts for the services.在这种情况下,当您为服务使用单独的上下文时,一旦涉及实体之间的关系,您就会总是遇到麻烦。

You can also create a single service which is responsible for a set of closely related entities, like an EmployeeCityService (which has a single context) and delegate the whole operation in your Button1_Click method to a method of this service.您还可以创建负责一组密切相关实体的单个服务,例如EmployeeCityService (具有单个上下文),并将Button1_Click方法中的整个操作委托给该服务的一个方法。

Steps to reproduce can be simplified to this:重现步骤可以简化为:

var contextOne = new EntityContext();
var contextTwo = new EntityContext();

var user = contextOne.Users.FirstOrDefault();

var group = new Group();
group.User = user;

contextTwo.Groups.Add(group);
contextTwo.SaveChanges();

Code without 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();

Using only one EntityContext can solve this.只使用一个EntityContext就可以解决这个问题。 Refer to other answers for other solutions.有关其他解决方案,请参阅其他答案。

This is an old thread, but another solution, which I prefer, is just update the cityId and not assign the hole model City to Employee... to do that Employee should look like:这是一个旧线程,但我更喜欢的另一种解决方案是更新 cityId,而不是将孔模型 City 分配给 Employee ......这样做 Employee 应该如下所示:

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

Then it's enough assigning:那么分配就足够了:

e1.CityId=city1.ID;

Alternatively to injection and even worse Singleton, you can call Detach method before Add.除了注入和更糟糕的单例之外,您可以在 Add 之前调用Detach方法。

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

EntityFramework 4: cs.Detach(city1); EntityFramework 4: cs.Detach(city1);

There is yet another way, in case you don't need first DBContext object.还有另一种方法,以防您不需要第一个 DBContext 对象。 Just wrap it with using keyword:只需使用关键字包装它:

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

I had the same problem but my issue with the @Slauma's solution (although great in certain instances) is that it recommends that I pass the context into the service which implies that the context is available from my controller.我遇到了同样的问题,但我对 @Slauma 解决方案的问题(尽管在某些情况下很好)是它建议我将上下文传递到服务中,这意味着上下文可从我的控制器获得。 It also forces tight coupling between my controller and service layers.它还强制我的控制器和服务层之间紧密耦合。

I'm using Dependency Injection to inject the service/repository layers into the controller and as such do not have access to the context from the controller.我正在使用依赖注入将服务/存储库层注入控制器,因此无法从控制器访问上下文。

My solution was to have the service/repository layers use the same instance of the context - Singleton.我的解决方案是让服务/存储库层使用上下文的相同实例 - 单例。

Context Singleton Class:上下文单例类:

Reference: http://msdn.microsoft.com/en-us/library/ff650316.aspx参考: http : //msdn.microsoft.com/en-us/library/ff650316.aspx
and http://csharpindepth.com/Articles/General/Singleton.aspxhttp://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;
    }
  }
}  

Repository Class:存储库类:

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

Other solutions do exist such as instantiating the context once and passing it into the constructors of your service/repository layers or another I read about which is implementing the Unit of Work pattern.确实存在其他解决方案,例如将上下文实例化一次并将其传递到服务/存储库层的构造函数中,或者我读到的另一个正在实现工作单元模式的方法。 I'm sure there are more...我确定还有更多...

In my case, I was using the ASP.NET Identity Framework.就我而言,我使用的是 ASP.NET Identity Framework。 I had used the built in UserManager.FindByNameAsync method to retrieve an ApplicationUser entity.我使用内置的UserManager.FindByNameAsync方法来检索ApplicationUser实体。 I then tried to reference this entity on a newly created entity on a different DbContext .然后,我尝试在不同DbContext上新创建的实体上引用此实体。 This resulted in the exception you originally saw.这导致了您最初看到的异常。

I solved this by creating a new ApplicationUser entity with only the Id from the UserManager method and referencing that new entity.我通过创建一个只有来自UserManager方法的Id的新ApplicationUser实体并引用该新实体来解决这个问题。

I had the same problem and I could solve making a new instance of the object that I was trying to Update.我遇到了同样的问题,我可以解决为我试图更新的对象创建一个新实例。 Then I passed that object to my reposotory.然后我将该对象传递给我的存储库。

In this case, it turns out the error is very clear: Entity Framework cannot track an entity using multiple instances of IEntityChangeTracker or typically, multiple instances of DbContext .在这种情况下,错误很明显:实体框架无法使用IEntityChangeTracker多个实例或通常的DbContext多个实例来跟踪实体。 The solutions are: use one instance of DbContext ;解决方案是:使用DbContext一个实例; access all needed entities through a single repository (depending on one instance of DbContext );通过单个存储库访问所有需要的实体(取决于DbContext一个实例); or turning off tracking for all entities accessed via a repository other than the one throwing this particular exception.或关闭对通过存储库访问的所有实体的跟踪,而不是抛出此特定异常的实体。

When following an inversion of control pattern in .Net Core Web API, I frequently find that I have controllers with dependencies such as:在 .Net Core Web API 中遵循控制模式反转时,我经常发现我的控制器具有依赖项,例如:

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;
}

and usage like和用法像

...
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!

Since all three repositories depend on different DbContext instances per request, I have two options to avoid the problem and maintain separate repositories: change the injection of the DbContext to create a new instance only once per call:由于所有三个存储库每个请求都依赖于不同的DbContext实例,因此我有两种选择来避免该问题并维护单独的存储库:更改 DbContext 的注入以每次调用仅创建一次新实例:

// services.AddTransient<DbContext, MyDbContext>(); <- one instance per ctor. bad
services.AddScoped<DbContext, MyDbContext>(); // <- one instance per call. good!

or, if the child entity is being used in a read-only manner, turning off tracking on that instance:或者,如果子实体以只读方式使用,请关闭对该实例的跟踪:

myEntity.Foo.Bar = await this.barRepo.GetBars().AsNoTracking().SingleOrDefault(b => b.Id == model.BarId);

I hit this same problem after implementing IoC for a project (ASP.Net MVC EF6.2).在为项目 (ASP.Net MVC EF6.2) 实施 IoC 后,我遇到了同样的问题。

Usually I would initialise a data context in the constructor of a controller and use the same context to initialise all my repositories.通常我会在控制器的构造函数中初始化一个数据上下文,并使用相同的上下文来初始化我的所有存储库。

However using IoC to instantiate the repositories caused them all to have separate contexts and I started getting this error.然而,使用 IoC 来实例化存储库导致它们都具有单独的上下文,我开始收到此错误。

For now I've gone back to just newing up the repositories with a common context while I think of a better way.现在,当我想到更好的方法时,我已经回过头来仅使用通用上下文来更新存储库。

在整个事务中使用相同的 DBContext 对象。

This is how I encountered this issue.这就是我遇到这个问题的方式。 First I need to save my Order which needs a reference to my ApplicationUser table:首先,我需要保存我的Order ,它需要引用我的ApplicationUser表:

  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

The problem is that I am initializing a new ApplicationDbContext to save my new Order entity:问题是我正在初始化一个新的 ApplicationDbContext 来保存我的新Order实体:

 ApplicationDbContext db = new ApplicationDbContext();
 db.Entry(entOrder).State = EntityState.Added;
 db.SaveChanges();

So in order to solve the problem, I used the same ApplicationDbContext instead of using the built-in UserManager of ASP.NET MVC.所以为了解决这个问题,我使用了同样的ApplicationDbContext,而不是使用ASP.NET MVC的内置UserManager。

Instead of this:取而代之的是:

user = UserManager.FindById(User.Identity.GetUserId());

I used my existing ApplicationDbContext instance:我使用了我现有的 ApplicationDbContext 实例:

//db instance here is the same instance as my db on my code above.
user = db.Users.Find(User.Identity.GetUserId()); 

For my scenario we have a solution with several applications referencing the same context.对于我的场景,我们有一个解决方案,其中包含多个引用相同上下文的应用程序。 I had to update the unity.config file adding lifetime type to the context.我必须更新 unity.config 文件,将生命周期类型添加到上下文中。

<lifetime type="PerResolveLifetimeManager" />

Error source:错误来源:

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

Hope someone saves some precious time希望有人能节省一些宝贵的时间

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 IEntityChangeTracker的多个实例不能引用一个实体对象。 在实体框架中 - An entity object cannot be referenced by multiple instances of IEntityChangeTracker. in entity framework “一个实体对象不能被 IEntityChangeTracker 的多个实例引用。” 删除时? - 'An entity object cannot be referenced by multiple instances of IEntityChangeTracker.' while deleting? 一个实体对象不能被 IEntityChangeTracker 的多个实例引用。 在多个条目上 - An entity object cannot be referenced by multiple instances of IEntityChangeTracker. On multiple entries IEntityChangeTracker的多个实例不能引用一个实体对象。 无线网 - An entity object cannot be referenced by multiple instances of IEntityChangeTracker. Wi IEntityChangeTracker的多个实例不能引用一个实体对象。 与EF6 - An entity object cannot be referenced by multiple instances of IEntityChangeTracker. with EF6 “IEntityChangeTracker的多个实例无法引用实体对象。” - “An entity object cannot be referenced by multiple instances of IEntityChangeTracker.” Entity Framework System.InvalidOperationException:&#39;一个IEntityChangeTracker的多个实例不能引用一个实体对象。 - Entity Framework System.InvalidOperationException : 'An entity object cannot be referenced by multiple instances of IEntityChangeTracker.' C#Entity“实体对象不能被IEntityChangeTracker的多个实例引用。” - C# Entity “entity object cannot be referenced by multiple instances of IEntityChangeTracker.” 实体框架“ IEntityChangeTracker的多个实例不能引用一个实体对象” - Entity Framework “An entity object cannot be referenced by multiple instances of IEntityChangeTracker” 实体框架:IEntityChangeTracker 的多个实例不能引用实体 object - Entity Framework: An entity object cannot be referenced by multiple instances of IEntityChangeTracker
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM