I made a model in my DB where I have employees, they have a relation to employments and the employments are connected to deadlines.
To generate the model for my C# application, I used the Scaffold-DbContext
command and set everything up properly.
Now I want to create new employees with their employments for specific deadlines.
When an employee already exists and has employments for that deadline, I delete these first, if they do not exist I create them fresh.
When I have to create employees with their employments everything works fine, but if I try to run it again, having all the employees already, it throws an error whenever I try to update the employee or even add the newly created employment to the DB I get an InvalidOperationException
.
The instance of entity type 'Deadline' cannot be tracked because another instance with the same key value for {'DeadlineId'} is already being tracked
I also checked the context in the change tracker where it gets added again, once it is contained ad unchanged and once as modified where it has the current employment in its employment list.
The creation of the employments is it's own function that gets called when the Employees are created and returns the employments as a HashSet.
The function that creates the employees has its own context and the function that creates the employments has its own context.
What is the reason why it adds the deadline again? Is the problem the existence of multiple contexts at once?
- Database used: Microsoft SQL Server
- EF Core version 6.0.7
- Target Framework: .NET 6.0
- Language: C#
- Output type: class library
Edit: Examplecode
//Getting employees to delete and add their employments again
var context = Bidok2Context.GetBidok2Context();
DpwEmployeeList.AddRange(context.DpwEmployees);
var targetDpwEmployeeList = DpwEmployeeList.Where(p => p.PersonNavigation == targetPerson && p.DpwId.ToString().Replace(" ", "") == key.Replace(" ",""));
var dpwEmployeeList = targetDpwEmployeeList.ToList();
DpwEmployee targetDpwEmployee;
targetDpwEmployee = dpwEmployeeList.First();
//Deleting the old employments
if (targetDpwEmployee.DpwEmployments
.Any(e => e.DpwEmploymentDeadlineNavigation == context.GetCurrentDeadline()))
{
context.DpwEmployments.RemoveRange(targetDpwEmployee.DpwEmployments);
targetDpwEmployee.DpwEmployments.Clear();
}
targetDpwEmployee.DpwEmployments = DpwEmployment.GetEmploymentListFromRows(value, _wbp, ColumnNameIndexes, targetDpwEmployee);
context.DpwEmployments.UpdateRange(targetDpwEmployee.DpwEmployments); //Tried AttachRange and UpdateRange neither worked
I left out unnecessary code between relevant stuff
//GetEmplymentListFromRows
var result = new HashSet<DpwEmployment>();
var context = Bidok2Context.GetBidok2Context();
var dpwDeadline = context.GetCurrentDeadline();
var employment = new DpwEmployment() { PNr = key, DpwEmploymentEmployeeNavigation = employee };
employment.DpwEmploymentDeadlineNavigation = dpwDeadline;
result.Add(employment);
context.DpwEmployments.Update(employment); //Here comes the Error, also tried Add and Update
context.SaveChanges();
Edit: Changetracker
In the changetracker of my contex there is a DebugView where the LongView shows me the following:
Deadline {DeadlineId: 1} Unchanged
DeadlineId: 1 PK
Deadline1: '30.06.2022 00:00:00'
FullYear: 'False'
IsActive: 'False'
BidokPeople: []
ContractorContracts: []
DpwEmployments: []
DpwRaws: []
LecturerContracts: []
Deadline {DeadlineId: 2} Modified
DeadlineId: 2 PK
Deadline1: '31.12.2022 00:00:00' Modified
FullYear: 'True' Modified
IsActive: 'True' Modified
BidokPeople: []
ContractorContracts: []
DpwEmployments: [{DpwEmploymentId: 3926}, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, <not found>, ...]
DpwRaws: []
LecturerContracts: []
Deadline {DeadlineId: 2} Unchanged
DeadlineId: 2 PK
Deadline1: '31.12.2022 00:00:00'
FullYear: 'True'
IsActive: 'True'
BidokPeople: []
ContractorContracts: []
DpwEmployments: [{DpwEmploymentId: -2147482646}]
DpwRaws: []
LecturerContracts: []
Deadline {DeadlineId: 3} Unchanged
DeadlineId: 3 PK
Deadline1: '30.06.2021 00:00:00'
FullYear: 'False'
IsActive: 'False'
BidokPeople: []
ContractorContracts: []
DpwEmployments: []
DpwRaws: []
LecturerContracts: []
As you can see there are 2 deadlines with DeadlineId: 2
that should not be and I do not add or attach a deadline to the deadlines DbSet at any point, EF Core does that by itself. How can I make it stop doing that or why does it do that?
Edit: Single context solution
Using a single context by giving the context as a parameter to the GetEmploymentListFromRows
function also doesn't work and gives the error at the same location, when adding the employments to the DbSet
.
CodePudding user response:
Why can't you just create a single DB Context and just use it as you are using others? Making multiple context of same db increase the ambiguity chances.
CodePudding user response:
The problem apparently originated from the way EF Core tracks entities.
At first I added the employments in their functions to the DbSet so that they get tracked and get their ID, but the employees are already tracked by the context and by adding the employee to the employment EF Core with its cycle dependencies then adds the employment to the employee and thus wants to track it because it is added to the employee and sees there is a deadline it can track and thus the doubled deadline is one from the employee that gets updated in the database and one from the employment that is freshly created.
So to solve it I just had to remove the line where I added the employment to the context as it is enough to just have one "masterentity" that is tracked by the context.
If the model is created database first then it has connections to each other, so just loading the employees from the db and adding the employments is enough to track everything properly.