IEntityChangeTracker의 여러 인스턴스에서 엔티티 오브젝트를 참조 할 수 없습니다. Entity Framework 4.1에서 관련 개체를 엔터티에 추가하는 동안
City와 관련된 직원 세부 정보를 저장하려고합니다. 그러나 연락처를 저장하려고 할 때마다 "ADO.Net Entity Framework IEntityChangeTracker의 여러 인스턴스에서 엔터티 개체를 참조 할 수 없습니다" 라는 예외가 발생 합니다.
나는 많은 게시물을 읽었지만 여전히해야 할 일에 대한 정확한 아이디어를 얻지 못했습니다 ... 저장 버튼 클릭 코드는 다음과 같습니다.
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();
... 생성자에 매개 변수를 사용하지 마십시오. 클래스 내에 컨텍스트를 생성한다고 생각합니다. 로드 할 때 city1
...
Payroll.Entities.City city1 = cs.SelectCity(...);
... city1
의에 컨텍스트 를 첨부합니다 CityService
. 나중에 city1
새 참조에 대한 참조로 Employee
e1
추가 e1
하고이 참조를 포함city1
하여의 컨텍스트에 추가 EmployeeService
합니다. 결과적으로 city1
예외가 불평하는 두 가지 다른 컨텍스트에 첨부되었습니다.
서비스 클래스 외부에서 컨텍스트를 작성하고 두 서비스 모두에서 컨텍스트를 삽입하고 사용하여이 문제를 해결할 수 있습니다.
EmployeeService es = new EmployeeService(context);
CityService cs = new CityService(context); // same context instance
서비스 클래스는 단일 엔터티 유형 만 담당하는 리포지토리와 비슷합니다. 이 경우 서비스에 별도의 컨텍스트를 사용할 때 엔티티 간의 관계가 시작 되 자마자 항상 문제가 발생합니다.
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.
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. 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:
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;
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. 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
and 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;
}
}
}
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...
Alternatively to injection and even worse Singleton, you can call Detach method before Add.
EntityFramework 6: ((IObjectContextAdapter)cs).ObjectContext.Detach(city1);
EntityFramework 4: cs.Detach(city1);
There is yet another way, in case you don't need first DBContext object. Just wrap it with using keyword:
Payroll.Entities.City city1;
using (CityService cs = new CityService())
{
city1 = cs.SelectCity(Convert.ToInt64(cmbCity.SelectedItem.Value));
}
In my case, I was using the ASP.NET Identity Framework. I had used the built in UserManager.FindByNameAsync
method to retrieve an ApplicationUser
entity. I then tried to reference this entity on a newly created entity on a different 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.
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
. The solutions are: use one instance of DbContext
; access all needed entities through a single repository (depending on one instance of 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:
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:
// 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);
Use the same DBContext object throughout the transaction.
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
'Programing' 카테고리의 다른 글
IIS를 디버깅 할 때 Visual Studio Attach 보안 경고 해제 (0) | 2020.06.04 |
---|---|
항상 git 자격 증명을 요구하는 Visual Studio Code (0) | 2020.06.04 |
의존적으로 타이핑하지 않는 이유는 무엇입니까? (0) | 2020.06.04 |
“node_modules”폴더가 git 저장소에 포함되어야합니다 (0) | 2020.06.04 |
JavaScript에서 Java의 Thread.sleep ()에 해당하는 것은 무엇입니까? (0) | 2020.06.04 |