简体   繁体   中英

How to add an object multiple times in different tables with Entity Framework Core [Tracking error]

To simplify, I have a "Project" type that can contain several "Manager" and several "Employee". Each Employee and Manager is composed of an "Id" and "Person" property.

        public class Project
        {
            ...
            public ObservableCollection<Manager> Managers { get; set; }
            public ObservableCollection<Employee> Employees { get; set; }
        }

        public class Manager
        {
            public int Id { get; set; }
            public Person Person { get; set; }
        }

        public class Employee
        {
            public int Id { get; set; }
            public Person Person { get; set; }
        }

        public class Person
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }

I retrieve the information about a project from the database in the following way:

Project project = context.Set<Project>()
                .Include(p => proj.Managers).ThenInclude(d => d.Person)
                .Include(p => proj.Employees).ThenInclude(e => e.Person)
                .FirstOrDefault(p => p.Id == id);

When I want to modify the Employees participating in the project I select the employee from a list of Persons

List<Person> Persons = context.Set<Person>().AsNoTracking().ToList();
...
theCurrentProject.Employees.Add(new Employee{ Person = theSelectedPerson});

Then when I call context.SaveChanges();, if the Person is already present in the list of Managers and I also add it to the Employees the following error occurs: The instance of type 'Person' cannot be tracked because another instance with the key value '{Id:x}' is already being tracked.

I'm doing something wrong but I can't see what. I understand that at the time of loading the information from the database the different "Persons" present in the project are "Tracked" by EF and therefore the person that comes from the list of Persons is not the same as the one already beeing tracked. That's why I tried to add AsNoTracking() but without success. "Persons" are read-only in this software (I don't need the tracking on them). How can I make this work? And also possibly how to tell EF that such or such object is read-only and that it should not try to modify (track) them? I have tried 4-5 different approaches but none of them solves my problem. thanks in advance !

Try this:

var employee=new Employee{ PersonId = theSelectedPerson.Id};

 context.Set<Employees>.Add(employee);
 context.SaveChanges();

// get saved employee

var savedEmployee = context.Set<Employees>()
.Include (p=>p.Person)
.AsNoTracking()
.FirstOrDefault(e=>e.Id=employee.Id);

//or

var savedEmployee = context.Set<Employees>()
.Include (p=>p.Person)
.AsNoTracking()
.FirstOrDefault(e=>e.PersonId=theSelectedPerson.Id);

but before this you have to fix the bug in the classes

public class Manager
        {
            public int Id { get; set; }
            public int PersonId { get; set; }
            public Person Person { get; set; }
        }

        public class Employee
        {
            public int Id { get; set; }
            public int PersonId { get; set; }
            public Person Person { get; set; }
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM