实体框架.Remove()与.DeleteObject()


Answers:


275

两种方法都可以“ 从数据库中删除项目 ”通常是不正确的。准确地说是这样的:

  • ObjectContext.DeleteObject(entity)将实体Deleted标记上下文。(这EntityStateDeleted后)。如果你打电话SaveChanges后EF发送SQL DELETE语句到数据库。如果没有违反数据库中的引用约束,则将删除该实体,否则将引发异常。

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

    • 如果该关系是可选的,即从数据库中的子级到父级引用的外键允许NULL值,则该外键将设置为null,并且如果您为调用SaveChangesNULLchildEntity将被写入数据库(即两者都被删除)。这是通过SQL UPDATE语句发生的。没有DELETE语句发生。

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

    • 如果关系被识别(它不一定需要然后,因为主键的任何部分不能是NULL)EF将标记childEntity作为Deleted为好。如果调用SaveChangesSQL DELETE语句,则会将其发送到数据库。如果没有违反数据库中的其他引用约束,则将删除该实体,否则将引发异常。

我实际上您链接的MSDN页面上的备注”部分有些困惑,因为它说:“ 如果关系具有参照完整性约束,则在从属对象上调用Remove方法会将关系和从属对象都标记为删除。 ”。这对我来说似乎不准确,甚至是错误的,因为上述所有三种情况都具有“ 参照完整性约束 ”,但仅在最后一种情况下,实际上删除了孩子。(除非它们与“ 从属对象 ”是指参与识别关系的对象,不过这将是一个不常见的术语。)


2
引用完整性Wikipedia:引用完整性是数据的一种属性,当满足该要求时,它要求关系(表)的一个属性(列)的每个值都作为另一个(或相同)关系(表)中另一个属性的值存在。 ),因此当关系为可选时,我们会违反数据完整性规则
Mohammadreza

3
@Mohammadreza:如果您将其解释NULL为“不是一个值”(而不是NULL我有时写得有点草率的“值”,那么“可选关系”与引用完整性的定义并不矛盾)。
Slauma

1
那么什么是EF Core版本ObjectContext.DeleteObject
乔纳森·艾伦

13

如果您确实想使用Deleted,则必须使外键为可空值,但最终将得到孤立的记录(这是一开始就不应该这样做的主要原因之一)。所以就用Remove()

ObjectContext.DeleteObject(entity)在上下文中将实体标记为Deleted。(此后将删除EntityState。)如果事后调用SaveChanges,EF会将SQL DELETE语句发送到数据库。如果没有违反数据库中的引用约束,则将删除该实体,否则将引发异常。

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

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


4
好吧,对于那些拒绝我的答案的人来说,这与Slauma无关- 他们俩都指向相同的文档。我的解释了现实生活中的例子,而他的理论部分。
Matas Vaitkevicius
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.