我有这两个模型:
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支持级联删除的唯一方法吗?
由于
答案 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?