如何使用 Entity Framework Core 在不同的表中多次添加对象 [跟踪错误]

Posted

技术标签:

【中文标题】如何使用 Entity Framework Core 在不同的表中多次添加对象 [跟踪错误]【英文标题】:How to add an object multiple times in different tables with Entity Framework Core [Tracking error] 【发布时间】:2021-07-10 15:41:11 【问题描述】:

为了简化,我有一个“项目”类型,可以包含多个“经理”和多个“员工”。每个 Employee 和 Manager 都由一个“Id”和“Person”属性组成。

        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; 
        

我通过以下方式从数据库中检索有关项目的信息:

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

当我想修改参与项目的员工时,我从人员列表中选择员工

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

然后,当我调用 context.SaveChanges(); 时,如果此人已经存在于经理列表中并且我还将它添加到员工中,则会发生以下错误:无法跟踪“人”类型的实例,因为另一个已在跟踪具有键值“Id:x”的实例。

我做错了什么,但我看不到是什么。我了解在从数据库加载信息时,项目中存在的不同“人员”被 EF “跟踪”,因此来自人员列表的人员与已经跟踪的人员不同。这就是为什么我尝试添加 AsNoTracking() 但没有成功。 “人”在这个软件中是只读的(我不需要跟踪他们)。我怎样才能使这项工作?还有可能如何告诉 EF 这样或这样的对象是只读的并且它不应该尝试修改(跟踪)它们? 我尝试了 4-5 种不同的方法,但没有一个能解决我的问题。 提前致谢!

【问题讨论】:

没有理由添加新员工。试试 :theCurrentProject.Employees.Add(theSelectedPerson; 我收到以下错误:“无法从个人转换为员工” 员工 ID 和个人 ID 相同吗?您需要获取该人员的员工对象,然后在没有新员工的情况下添加员工。 【参考方案1】:

试试这个:

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

但在此之前,您必须修复类中的错误

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; 
        

【讨论】:

感谢您的回答。我添加了 PersonId,现在我没有收到跟踪错误。但是通过仅在新 Employee 中插入 PersonId,Person 属性为 null,直到调用 context.SaveChange()。因此,在调用 context.SaveChange() 之前,我无法读取 Person 对象的 Name 属性。有没有办法解决这个问题? 本应如此。我看不出有什么问题。您已经有了 SelectedPerson。你还需要什么? @Bruno 我做了一些更新。如果有帮助,请告诉我。 感谢您的帮助,确实可以完美运行。从现在开始,我将与 Id 合作。

以上是关于如何使用 Entity Framework Core 在不同的表中多次添加对象 [跟踪错误]的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework 学习系列 - 认识理解Entity Framework

如何使用 Entity Framework Core 模拟异步存储库

如何使用 Entity Framework 生成和自动递增 Id

如何使用 Entity Framework Core 正确保存 DateTime?

如何使用 Entity Framework Core 获取主键值

如何在 Entity Framework 6 中使用 DbDataReader 获取表名?