【问题标题】:Deleting Optional 1-to-Many Does Not Set Foreign Key to Null删除可选的一对多不会将外键设置为空
【发布时间】:2015-07-20 23:50:52
【问题描述】:

我有两个实体具有可选的一对多关系定义和配置如下:

public class A 
{
   // ...
   public int? BId { get; set; }
   public B B { get; set; }
}

public class B 
{
   // ...
   public virtual ICollection<A> As { get; set; }
}


public class AConfiguration : EntityTypeConfiguration<A>
{
     public A() 
     {
         // ...
         HasOptional(r => r.B).WithMany(r => r.As).HasForeignKey(r => r.BId);
     }
}

在删除类型 B 的实体时,我希望所有类型 A 的实体都具有被删除的 B 实体的外键,并将 BId 外键设置为 null。删除操作是这样定义的:

public void DeleteB(int bId)
{
    var entity = _context.Bs.Single(b => b.Id == bId);
    _context.Bs.Remove(entity);
    _context.SaveChanges();
}

但是这不会发生。 B 类型的实体已成功删除,但 A 实体上的 BId 仍为非 null,任何其他对 .SaveChanges() 的调用都会引发异常,因为这些 BId 正在引用不再存在的行。

如何删除 B 实体,使 BId 属性无效,而无需在删除操作期间手动迭代集合?

【问题讨论】:

    标签: c# sql-server entity-framework ef-code-first


    【解决方案1】:

    仅当当前关联的实体已经加载到上下文中时,外键才会自动设置为 null。换句话说,当b 被删除时,如果A 类型的实体已经加载到上下文中,则A 类型的关联集只会将它们的BId 属性设置为null。否则,EF 将不知道它们的存在(除非 EF 提供程序自动生成 SQL,将这些外键设置为 null...在 SQL Server 的情况下它不会)。

    一种选择是这样做(如果您不介意加载所有这些实体):

    public void DeleteB(int bId)
    {
        var entity = _context.Bs.Single(b => b.Id == bId);
        _context.Entry(entity).Collection(b => b.As).Load(); 
        _context.Bs.Remove(entity);
        _context.SaveChanges();
    }
    

    另一种选择是编写自己的 SQL 语句并运行它。

    【讨论】:

    • 我可以在 A 表上运行 update A a set a.BId = NULL where a.BId = @bId 作为 before delete 触发器。
    猜你喜欢
    • 2013-03-22
    • 1970-01-01
    • 1970-01-01
    • 2012-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-14
    相关资源
    最近更新 更多