实体框架DbContext .Remove(obj)vs .Entry(obj).State = EntityState.Deleted

时间:2014-07-15 10:23:28

标签: c# entity-framework

我首先使用EF代码。一个简单的模型:

  item { public int Id {set; get;},... ,ICollection<ItemImages> {set; get;} }

    itemImages { 
         public int Id {set; get; },
         public int ItemId {set; get; }
          , ... ,
         public Item Item  {set; get; }
      }

ItemConfig:EntityTypeConfiguration<Item>
{
 //some config statement;
 //...
// mark child delete when parent delete: waterfall delete.
 HasRequired(rs => rs.ItemCat).WithMany(rs => rs.Items).HasForeignKey(rs => rs.ItemCatId).WillCascadeOnDelete(true);
}

当通过删除()删除实体时,它会很好地删除项目和相关子项(项目图像记录)。

_db.Item.Remove(DeleteThisObj);
_db.SaveChanges();

但是当标记为删除时:

_db.Entry(DeleteThisObj).State = EntityState.Deleted;
_db.SaveChanges();

得到错误:

  

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

1 个答案:

答案 0 :(得分:14)

如果你真的想使用Deleted,你必须让你的外键可以为空,但是你最终会得到孤立的记录(这是你不应该做的主要原因之一)首先要这样做)。所以只需使用Remove()

ObjectContext.DeleteObject(entity)在上下文中将实体标记为已删除。 (之后它的EntityState被删除。)如果之后调用SaveChanges,EF会向数据库发送一个SQL DELETE语句。如果违反了数据库中的引用约束,则将删除该实体,否则将引发异常。

EntityCollection.Remove(childEntity)将parent和childEntity之间的关系标记为已删除。如果从数据库中删除了childEntity本身,并且在调用SaveChanges时究竟发生了什么,取决于两者之间的关系类型:

如果关系是可选的,即从子级引用到数据库中的父级的外键允许NULL值,则此外部将设置为null,如果调用SaveChanges,则将为childEntity写入此NULL值数据库(即两者之间的关系被删除)。使用SQL UPDATE语句会发生这种情况。没有DELETE语句。

如果需要关系(FK不允许NULL值)并且关系未识别(这意味着外键不是子组件(复合)主键的一部分)您必须要将子项添加到另一个父项,或者必须显式删除子项(然后使用DeleteObject)。如果你不做这些中的任何一个,就会违反参考约束,当你调用SaveChanges时,EF会抛出一个异常 - 臭名昭着的&#34;由于一个或多个外键属性是,所以关系无法改变。不可为空&#34;例外或类似。

如果关系正在识别(因为主键的任何部分都不能为NULL,则必然需要),EF也会将childEntity标记为已删除。如果调用SaveChanges,则会将SQL DELETE语句发送到数据库。如果数据库中没有违反其他参照约束,则将删除该实体,否则将引发异常。

值得注意的是设置.State = EntityState.Deleted does not trigger automatically detected change.