删除关系时删除依赖实体

时间:2011-09-07 05:00:32

标签: c# entity-framework-4.1 ef-code-first foreign-key-relationship

说我有两个这样的实体:

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

让实体不仅删除关系,还删除Response实体。目前,如果我删除该关系,我会收到以下错误:

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

阅读此博客文章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()并标记删除任何已删除患者关系的响应。我试过这个:

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.Patient的响应,实体不会加载Response.Patient属性,所以我的代码认为它已经被孤立并且应该被删除。

总结

我想知道的是,如何修改实体,因为它的FK关系已被删除。

3 个答案:

答案 0 :(得分:2)

请改用:

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

答案 1 :(得分:1)

您需要配置映射,以便进行级联删除。为此,您需要将模型与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);
    }
}

答案 2 :(得分:1)

我认为我的问题不在于代码,而在于我假设实体的Attach()方法是如何工作的。我假设如果我附加了PatientId设置而不是Patient属性的响应,那么实体将为我填充Patient属性。

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