关系删除时移除依赖实体

本文关键字:依赖 实体 删除 关系 | 更新日期: 2023-09-27 18:08:02

假设我有两个实体:

public class Response 
{
  public int Id { get; set; }
  public int PatientId { get; set; }
  public virtual Patient Patient { get; set; }
  public string Text { get; set; }
}
public class Patient
{
  public int Id { get; set; }
  public string Name { get; set; }
  public virtual ICollection<Response> Responses { get; set; }
}

我想要能够调用

Patient.Responses.Remove(someResponse);

并让实体不仅删除关系,而且删除响应实体。目前,如果我只是删除关系,我得到以下错误:

系统。InvalidOperationException:操作失败:不能更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性被设置为空值。如果外键不支持空值,则必须定义一个新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

阅读这篇博客文章http://blogs.msdn.com/b/dsimmons/archive/2010/01/31/deleting-foreign-key-relationships-in-ef4.aspx我意识到我可以通过以下映射来实现这一点:

modelBuilder.Entity<Response>().HasKey(m => new { m.Id, m.PatientId }); 

但是我不想改变主键。我要做的是重写DbContext.SaveChanges(),并将删除Patient关系的任何响应标记为删除。我试过了:

public override int SaveChanges()
{
  // Need to manually delete all responses that have been removed from the patient, otherwise they'll be orphaned.
  var orphanedResponses = ChangeTracker.Entries().Where(
    e => e.State == EntityState.Modified &&
      e.Entity is Response &&
        e.Reference("Patient").CurrentValue == null);
  foreach (var orphanedResponse in orphanedResponses)
  {
    Responses.Remove(orphanedResponse.Entity as Response);
  }
  return base.SaveChanges();
}

但是我发现可以只附加Response。设置PatientId而不是Response。病人,实体没有加载响应。所以我的代码认为它是孤立的,应该被删除。

总之

我想知道的是我怎样才能知道一个实体已经被修改了,因为它的FK关系已经被删除了

关系删除时移除依赖实体

用这个代替:

public override int SaveChanges()
{
    var responses = Responses.Local.Where(r => r.Patient == null);
    foreach (var response in responses.ToList())
    {
        Responses.Remove(response);
    }
    return base.SaveChanges();
}

您需要配置映射,以便发生级联删除。要做到这一点,您需要将具有WillCascadeOnDelete的模型映射到true

public class MyContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Patient>()
           .HasMany(patient=> patient.Responses)
           .WithRequired(response => response.Patient)
           .HasForeignKey(response => response.PatientId)
           .WillCascadeOnDelete(true);
    }
}

我认为我的问题不是代码,而是我如何假设实体的Attach()方法工作。我假设如果我附加一个带有PatientId集合但没有Patient属性的响应,那么实体将为我填充Patient属性。

事实上,我认为发生的是实体附加它,然后如果我将该实体标记为已修改并保存它,实体看到null Patient属性并假设我想要删除关系,因此抛出一个错误,因为它将被孤立(不能null Response.PatientId)。因此,也许一切都按照设计工作,并且我的SaveChanges()解决方案工作。