实体框架DbContext .Remove(obj)vs .Entry(obj).State = EntityState.Deleted [英] Entity Framework DbContext .Remove(obj) vs .Entry(obj).State = EntityState.Deleted

查看:257
本文介绍了实体框架DbContext .Remove(obj)vs .Entry(obj).State = EntityState.Deleted的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我第一次使用EF代码。一个简单的模型:

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

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

ItemConfig:EntityTypeConfiguration< Item>
{
//一些配置语句;
// ...
//父删除时标记子删除:瀑布删除。
HasRequired(rs => rs.ItemCat).WithMany(rs => rs.Items).HasForeignKey(rs => rs.ItemCatId).WillCascadeOnDelete(true);
}

当通过 Remove()删除实体时,删除项目和相关的孩子(项目图像记录)。

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

但标记为删除时:

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

获取错误:


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



解决方案

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



ObjectContext.DeleteObject(entity)将上下文中的实体标记为已删除。 (之后删除它的EntityState。)如果之后调用SaveChanges,EF会向数据库发送SQL DELETE语句。如果数据库中没有引用限制被违反,则实体将被删除,否则抛出异常。



EntityCollection.Remove(ChildEntity)将父项和childEntity之间的关系标记为已删除。如果childEntity本身从数据库中删除,并且调用SaveChanges时会发生什么事情取决于两者之间的关系:



如果关系是可选的,即从数据库中的子对象引用的外键允许NULL值,这个外部设置为null,如果调用SaveChanges,childEntity的NULL值将被写入数据库(即两个关系被删除)。这发生在SQL UPDATE语句中。没有DELETE语句发生。



如果需要关系(FK不允许NULL值),并且关系不是标识(这意味着外键不是孩子(复合)主键的一部分),您必须将该子项添加到另一个父项,或者您必须显式地删除该子(然后使用DeleteObject)。如果不执行任何这些引用约束违反,并且EF将在调用SaveChanges时引发异常 - 臭名昭着的因为一个或多个外键属性不可为空异常而无法更改关系异常或类似的。



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



值得注意的一点是,设置 .State = EntityState.Deleted 不会触发自动检测到的更改


I'm using EF Code first. a simple model:

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

when delete entity by Remove(), it delete item and related child (item images records) well.

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

but when mark it to delete:

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

get error:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

解决方案

If you really want to use Deleted, you'd have to make your foreign keys nullable, but then you'd end up with orphaned records (which is one of the main reasons you shouldn't be doing that in the first place). So just use Remove()

ObjectContext.DeleteObject(entity) marks the entity as Deleted in the context. (It's EntityState is Deleted after that.) If you call SaveChanges afterwards EF sends a SQL DELETE statement to the database. If no referential constraints in the database are violated the entity will be deleted, otherwise an exception is thrown.

EntityCollection.Remove(childEntity) marks the relationship between parent and childEntity as Deleted. If the childEntity itself is deleted from the database and what exactly happens when you call SaveChanges depends on the kind of relationship between the two:

If the relationship is optional, i.e. the foreign key that refers from the child to the parent in the database allows NULL values, this foreign will be set to null and if you call SaveChanges this NULL value for the childEntity will be written to the database (i.e. the relationship between the two is removed). This happens with a SQL UPDATE statement. No DELETE statement occurs.

If the relationship is required (the FK doesn't allow NULL values) and the relationship is not identifying (which means that the foreign key is not part of the child's (composite) primary key) you have to either add the child to another parent or you have to explicitly delete the child (with DeleteObject then). If you don't do any of these a referential constraint is violated and EF will throw an exception when you call SaveChanges - the infamous "The relationship could not be changed because one or more of the foreign-key properties is non-nullable" exception or similar.

If the relationship is identifying (it's necessarily required then because any part of the primary key cannot be NULL) EF will mark the childEntity as Deleted as well. If you call SaveChanges a SQL DELETE statement will be sent to the database. If no other referential constraints in the database are violated the entity will be deleted, otherwise an exception is thrown.

A thing worth noting is that setting .State = EntityState.Deleted does not trigger automatically detected change.

这篇关于实体框架DbContext .Remove(obj)vs .Entry(obj).State = EntityState.Deleted的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆