使用实体框架删除级联

时间:2014-10-31 14:28:58

标签: asp.net-mvc entity-framework asp.net-mvc-5

我有这两个模型:

public partial class Country
{
        public Country()
        {
            this.Dinners = new HashSet<Dinner>();
        }

        public int CountryID { get; set; }
        public string Name { get; set; }
        public virtual ICollection<Dinner> Dinners { get; set; }
}

public partial class Dinner
{
        public Dinner()
        {
            this.TRsvps = new HashSet<TRsvp>();
        }

        public int DinnerID { get; set; }
        public System.DateTime EventDate { get; set; }
        public string Description { get; set; }
        public string HostedBy { get; set; }
        public Nullable<int> CountryID { get; set; }

        public virtual Country Country { get; set; }
}

当用户尝试删除具有子记录(Country)的父实体(在我们的例子中是Dinners实体)时,我对Entity Framework的行为方式感到有些困惑。 / p>

例如,如果我的mvc操作方法中包含以下代码: -

public ActionResult DeleteConfirmed(int id)
{
    Country country = db.Countries.Find(id);
    db.Countries.Remove(country);
    db.SaveChanges();
    return RedirectToAction("Index");
}

如果我尝试删除一个有晚餐的国家/地区,则会引发例外情况,这听起来有效。

我尝试通过在检索Dinners对象时包含Country来修改我的代码如下:

Country country = db.Countries.Include(a => a.Dinners).Single(a2 => a2.CountryId = id);
db.Countries.Remove(country);
db.SaveChanges();
return RedirectToAction("Index");

不会引发异常,所以我认为EF会删除儿童晚餐,但会发生的事情是它将countryID表中的Dinners FK更新为null .... (Cascade Set to Null

我尝试按如下方式循环遍历Dinners集合:

 public ActionResult DeleteConfirmed(int id)
 {
     Country country2 = db.Countries.Find(id) ;

     foreach(var d in country2.Dinners)
     {
         db.Dinners.Remove(d);
     }

     db.Countries.Remove(country2);
     db.SaveChanges();
     return RedirectToAction("Index");
}

但这引发了以下错误:

  

类型&#39; System.InvalidOperationException&#39;的例外情况发生在   System.Core.dll但未在用户代码中处理

     

其他信息:收集已修改;枚举操作   可能无法执行。

我意识到我应该在foreach上明确调用.Tolist()来删除父项及其所有子项,如下所示:

 foreach(var d in country2.Dinners.ToList())

如果我弄错了,有人可以提出建议,或者这是使用EF支持级联删除的唯一方法吗?

由于

2 个答案:

答案 0 :(得分:1)

如果您希望自动级联删除,请在OnModelCreating方法中手动启用它:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Country>().WillCascadeOnDelete(true);
}

答案 1 :(得分:1)

当外键可以为空时,您正在描述级联删除的记录行为:

  

如果依赖实体上的外键可以为空,则Code First会这样做   没有在关系上设置级联删除,当主体是   删除外键将被设置为null。

如果您希望它级联删除,则需要关系,并且外键不应该为空。将public Nullable<int> CountryID { get; set; }更改为public int CountryID { get; set; }

参考:

http://msdn.microsoft.com/en-us/data/jj591620.aspx#CascadeDelete

发表评论后的其他信息 您不必.Include进行级联删除以处理所需的关系,即。一旦你使外键不可为空。我确信这是因为这就是我的应用程序的工作方式。

我认为您正在观察Remove标记要删除的整个对象图 - 无论是否需要 - 与Add标记整个图形以进行插入的方式相同。注意 - 我不是100%肯定这一点所以你应该在依赖它之前测试它。

进一步阅读:

using Dbset.Add Versus using EntityState.Added

Why Does Entity Framework Reinsert Existing Objects into My Database?

What is the difference between IDbSet.Add and DbEntityEntry.State = EntityState.Added?