保存相关记录而不创建重复的主体记录

时间:2018-11-29 17:11:21

标签: entity-framework entity-framework-core

使用EF Core,我正在创建主体记录,但是在添加和保存从属记录时,它将尝试创建新的重复主体。

我已经看到了各种解决方案,但是我想知道为什么会这样来解决问题。

实体模型采用这种方式。

public class Company
{
    public string ID { get; set; }
    public string Name { get; set; }
}

public class Employee
{
    public string ID { get; set; }
    public string Title { get; set; }
    public string Name { get; set; }

    public string CompanyID { get; set; }

    [ForeignKey("CompanyID")]
    public Company Company { get; set; }
}

创建了DbContext,以将其中的DbSet公开。

public class OrganizationContext : DbContext
{
    public DbSet<Company> Companies { get; set; }
    public DbSet<Employee> Employees { get; set; }

    // ...
}

从视图传递完整对象以通过OrganizationContext将雇员添加到公司时,它也会尝试创建新的公司记录。

var comp = new Company()
{
    comp.ID = "1",
    comp.Name = "The Daily Planet"
};

var emp = new Employee()
{
    emp.ID = "00123",
    emp.Title = "Supervisor",
    emp.Name = "Clark Kent",
    emp.CompanyID = "1",
    emp.Company = comp
};

_context.Employees.Add(emp);
_context.SaveChanges();

如果我将Company属性设置为不变,它仍会尝试插入新的Company。

_context.Employees.Add(emp);
_context.Entry(emp.Company).State = EntityState.Unchanged;
_context.SaveChanges();

如果我将emp.Company设置为null,它将不会尝试添加新公司

emp.Company = null;
_context.Employees.Add(emp);

是否存在正确的方法来建立模型关系或结构以向公司添加员工,而无需在保存之前手动更改对象图?

1 个答案:

答案 0 :(得分:3)

这是因为您正在使用Add方法,该方法通过definitionAdd操作级联到每个可到达的实体:

  

如果您创建几个新的相关实体,将其中一个添加到上下文中也会导致其他实体也被添加。

如果您使用的是带有自动生成的PK的实体,则正确的方法是使用Mix of new and existing entities中所述的Update方法:

  

使用自动生成的键,即使图形包含需要插入的实体和需要更新的实体的混合,更新也可以再次用于插入和更新

后跟一个示例,然后:

  

如果没有设置键值,更新将标记图形,博客或帖子中的任何实体以供插入,而将所有其他实体标记为要更新。

不幸的是,您的情况有所不同。没有通用的现成方法可以执行添加或更新。一种解决方案是不设置导航属性,而仅设置FK属性(幸运的是):

//var comp = new Company()
//{
//    comp.ID = "1",
//    comp.Name = "The Daily Planet"
//};

var emp = new Employee()
{
    emp.ID = "00123",
    emp.Title = "Supervisor",
    emp.Name = "Clark Kent",
    emp.CompanyID = "1",
    //emp.Company = comp
};

_context.Employees.Add(emp);
_context.SaveChanges();

另一种会导致数据库往返的费用的方法是从上下文中解析相关的现有实体:

var comp = _context.Companies.Find("1");

var emp = new Employee()
{
    emp.ID = "00123",
    emp.Title = "Supervisor",
    emp.Name = "Clark Kent",
    //emp.CompanyID = "1", // Not needed, but won't hurt if you include it
    emp.Company = comp
};

_context.Employees.Add(emp);
_context.SaveChanges();

最后一个选择是使用TrackGraph并为每个实体单独决定。

相关问题