【问题标题】:Entity Framework recursive Relations and Attaching errors实体框架递归关系和附加错误
【发布时间】:2018-03-31 15:29:00
【问题描述】:

我正在使用 WPF 和 EF 6.2.0 创建一个应用程序来管理项目、员工并将员工分配给项目。

所以我有一个具有不同属性的Employee 实体(其中一些是对其他实体的引用),我有一个具有不同属性的Project 实体(同样,其中一些是其他实体)。

这是我的数据库方案:

现在我想创建一个Job 实体,该实体分配给EmployeeProject。 因此,要添加一个,我必须将整个 EmployeeProject 实体(包括所有它们引用的实体)附加到我的上下文中,然后才能添加 Job 对吗?

如果我不这样做或忘记实体的关系/属性之一,它会尝试在数据库上创建整个实体,并抛出一些错误,例如该员工的主键已经存在(显然,因为它应该'不要创建它,而是附加现有的本地)

另一方面,如果我尝试附加它,附加 Project 时它会失败,因为(现在是疯狂的部分)Project.CostCentre.Location.CostCentres[0].Projects[0].Contact (Employee) 已经附加。它试图以递归方式附加每一件事,包括所有列表?!

这是导致此问题的堆栈跟踪:

private void Attach(Job job, bool attachEntity = true)
{
    Attach(job.Employee);
    Attach(job.Project); // Calls next func
    if (attachEntity && !Attached(job))
        Context.Jobs.Attach(job);
}

private void Attach(Project project, bool attachEntity = true)
{
    Attach(project.Contact);
    Attach(project.CostCentre); // Calls next func
    Attach(project.CostType);
    Attach(project.Status);
    if (attachEntity && !Attached(project))
        Context.Projects.Attach(project);
}

private void Attach(CostCentre costCentre, bool attachEntity = true)
{
    Attach(costCentre.Location); // Calls next func
    if (attachEntity && !Attached(costCentre))
        Context.CostCentres.Attach(costCentre);
}

private void Attach(Location location, bool attachEntity = true)
{
    if (attachEntity && !Attached(location))
        Context.Locations.Attach(location); // The error (that code tries to attach location.CostCentres[0].Projects[0].Contact aswell, which is an already attached Employee!!)
}

完整的错误信息:

System.InvalidOperationException: 'Attaching an entity of type 'ForecastLibrary.Employee' failed because another entity of the same type already has the same primary key value.
This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values.
This may be because some entities are new and have not yet received database-generated key values.
In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.'

完整的源代码在这里:https://pastebin.com/8YU0xQUC

我已经尝试解决这个晦涩的错误几个星期了,我希望这里有人可以帮助我成功添加这个Job

编辑:这是调用所有这些的代码:

// DataService::Add Function
public void Add(Job job)
{
    Attach(job, false);
    Context.Jobs.Add(job);
}

// UI Add job snippet
using (var service = new DataService(Session.ConnectionString))
{
    service.Add(JobToAdd);
    await service.SaveAsync();
}

【问题讨论】:

  • 它正在尝试添加员工。您是否在同一个上下文实例中从 db 加载了员工?您可以通过context.Entry(employee).State = EntityState.Unchanged 告诉上下文它已经存在并且它不会添加它。但是,这更像是修复您自己的设计错误,因此更好的方法是找出 EF 认为这是 q 新实体的原因。
  • 为什么要手动附加实体? EF 自动附加所有子项,因此您在发布的代码之外做错了什么
  • @CodingYoshi 是的,我确实从另一个上下文加载了员工。所以你的意思是我不需要任何附件,只需要在添加作业之前输入context.Entry(employee).State = EntityState.Unchanged
  • @CamiloTerevinto 它是如何自动附加的?你能进一步解释一下吗?
  • @CamiloTerevinto 查看我的编辑。我认为我没有做任何奇怪的事情

标签: c# .net database entity-framework logic


【解决方案1】:

如果您确切知道自己需要什么并且拥有更大的数据模型,我建议您使用 Eager loading。

DataService 的构造函数中调用Context.Configuration.LazyLoadingEnabled = false; 并在需要导航属性的任何地方使用.Include

那么你需要使用Find而不是Attach

所以您的 Job Add 功能可能如下所示:

public void Add(Job job)
{
    var employee = Context.Employees.Find(job.Employee.Id);
    var project = Context.Projects.Find(job.Project.Id);
    Context.Jobs.Add(new Job { Employee = employee, Project = project, Time = job.Time });
}

【讨论】:

    猜你喜欢
    • 2018-06-06
    • 2015-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-13
    • 1970-01-01
    • 2020-09-26
    • 1970-01-01
    相关资源
    最近更新 更多