如何使用 EF Core 3+ 中具有状态(修改、添加、删除)的 request/body 自定义对象的相关数据(数组)更新实体?

How to update an entity with related data (arrays) from request/body custom objects with states (modified, added, removed) in EF Core 3+?

我的对象的简化版本:

public class CV 
{
  public int Id {get;set;}
  public string Name {get;set;}
  public List<Certificate> Certificates {get;set;}
  public List<Experience> Experiences {get;set;}
}
public class Certificate 
{
  public int Id {get;set;}
  public string Name {get;set;}
}
public class Experience 
{
  public int Id {get;set;}
  public string Name {get;set;}
  public List<SkillExperience> Skills {get;set;}
}
public class SkillExperience
{
  public int SkillId {get;set;}
  public int ExperienceId {get;set;}
  public bool isCore {get;set;}
}
public class Skill 
{
  public int Id {get;set;}
  public string Name {get;set;}
}

来自请求的主体(来自前端)的以下对象(再次真正简化):

public class CvRequest 
{
  public int Id {get;set;}
  public string Name {get;set;}
  public CertificateRequest Certificates {get;set;}
  public ExperienceRequest Experiences {get;set;}
}
public class CertificateRequest
{
  public List<Certificate> AddedCertificates {get;set;}
  public List<Certificate> ModifiedCertificates {get;set;}
  public List<int> RemovedCertificateIDs {get;set;}
}
// the ExperienceRequest is a little more complex because it has a many-to-many relationship, so I won't show it
// but it's similar, the question is related to it, but it has the same pattern of modified/added/removed

我有通用存储库模式(架构),所以我遍历添加实体列表并调用 conext.Set.Add(实体),我遍历修改后调用更新,我循环遍历删除的 ID并调用按 ID 删除。

problem/question:

问题是我使用 .Include(cv => cv.Certificate) 访问 CV 以及所有相关数据。然后我调用 cvRepository.Update(cvRequest.ToEntity<CV>()); 并且 它有效 ,但是当我调用 certificateRepository.Update(new Certificate(){...}); 时它说:

System.InvalidOperationException: The instance of entity type 'Certificate' cannot be tracked because another instance with the key value '{Id: 5}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

由于它是与已跟踪实体的相关数据,我无法自行更新它。我不能 cv.Certificates.Update(certificate) 或类似的东西,我只能直接访问 DbSet。我试过 {context_name}.Entry(entity).State = EntityState.Detached; 我也试过 AsNoTracking.

多对多呢?那里更糟。还有更深层次的嵌套和跟踪管理。

这个呢?

在 EF Core 3+ 中更新实体的相关数据(以及相关数据的相关数据)的最佳方式是什么?

我应该使用 {context_name}.Entry(entity).CurrentValues.SetValues(modifiedEntity); 而不是 Update(modifiedEntity); 吗?

我认为您 运行 遇到的问题是您尝试第二次跟踪 ID=5 的证书,尽管它已经通过调用进行跟踪

certificateRepository.Update(new Certificate(){...});

基本上它已经用 .Include(cv => cv.Certificate) 加载和跟踪了,您尝试通过创建一个新对象并调用来再次跟踪它更新您的存储库。

在这种情况下,您可以操作使用 cvRequest 加载的证书并调用 SaveChanges,而无需在实体的新对象上显式调用 "Update"。 EF Core 将为您管理跟踪并注意到它已更改并更新它。