如何在不先加载对象的情况下从实体框架模型中删除一个对象?

40

我很确定我在某个地方看到了这个问题的答案,但是由于我在Stack Overflow或Google上进行几次搜索都没有找到它,所以我还是要再次询问...

在Entity Framework中,删除数据对象似乎唯一的方法是

MyEntityModel ent = new MyEntityModel();
ent.DeleteObject(theObjectToDelete);
ent.SaveChanges();

然而,这种方法需要先将对象加载到控制器(Controller)中,才能删除它。有没有一种方法可以通过仅引用其ID来删除业务对象(Business Object)?

如果使用Linq或Lambda表达式更聪明的方式,那也是可以的。但主要目标是避免加载数据以便删除它。


2
有一种好的通用方法可以实现这个:http://j.mp/f0x0Bh - BritishDeveloper
@BritishDeveloper:有意思!不过,当被问及此问题时,我已经意识到,如果涉及外键关系,检索实体通常有充分的理由。 - Tomas Aschan
可能是如何使用Entity Framework按ID删除对象的重复问题。 - Michael Freidgeim
@MichaelFreidgeim:是的,除了这个问题是一年前问的... - Tomas Aschan
“可能是重复问题”是一种整理方式 - 关闭类似的问题并保留最佳答案。日期并不重要。请参见http://meta.stackexchange.com/questions/147643/should-i-vote-to-close-a-duplicate-question-even-though-its-much-newer-and-ha 如果您认为需要澄清,请在http://meta.stackexchange.com/questions/281980/add-clarification-link-to-possible-duplicate-automated-comment上投票。 - Michael Freidgeim
7个回答

19

值得知道的是,Entity Framework支持Linq to Entities和Entity SQL。如果你想要执行可能影响许多记录的删除或更新操作,可以使用与ExecuteNonQuery等效的方法。

在Entity SQL中,可能看起来像这样:

   Using db As New HelloEfEntities

        Dim qStr = "Delete " & _
                  "FROM Employee"
        db.ExecuteStoreCommand(qStr)
        db.SaveChanges()
    End Using
在这个例子中,db 是我的 ObjectContext。还要注意,ExecuteStoreCommand 函数可以接受一个可选的参数数组。

在这个例子中,db 是我的 ObjectContext。还要注意,ExecuteStoreCommand 函数可以接受一个可选的参数数组。


2
此答案直接回答了提问者想要做的事情,并应标记为被接受的答案。其他解决方案,如从无到有构建实体,不够优化。同时请查看http://msdn.microsoft.com/en-us/library/ee358769.aspx - mare
17
为什么在执行ExecuteStoreCommand之后要调用SaveChanges? - epotter
3
这不是一个好的答案。它会让你的代码容易受到 SQL 注入攻击。并且你没有 EF 的前两个优势之一:在编译时进行语法检查。 - Jurion

8
我找到了这篇文章,它说明确实没有更好的删除记录的方法。给出的解释是,所有与该记录唯一相关的外键、关系等也会被删除,因此EF需要正确的信息来处理该记录。我对为什么不能在不加载数据的情况下实现这一点感到困惑,但由于这种情况并不经常发生,所以我决定(暂时)不去烦恼它。
如果您有解决这个问题的方法,请随时告诉我 =)

3
使用存储过程怎么样? - Pure.Krome

4
您可以创建一个具有相同ID的对象,并将其传递给delete。但是,如果您有复杂的关系,则可能需要更多。
                var user = new User { ID = 15 };
                context.Entry(user).State = EntityState.Deleted;
                context.SaveChanges();

4

有一种方法可以通过重新计算实体的EntityKey来欺骗加载实体。这看起来有点像黑客技巧,但可能是在EF中实现此操作的唯一方法。

关于无需获取即可删除的博客文章。


4

提前道歉,但我必须质疑您的目标。

如果您在未阅读对象的情况下删除它,则无法知道另一个用户是否在您确认要删除该对象并实际删除之间更改了该对象。在“普通的 SQL”中,这就像执行以下操作:

DELETE FROM FOO
WHERE ID = 1234

当然,大多数人并不会真正这样做。相反,他们会做类似于以下的事情:
DELETE FROM FOO
WHERE ID = 1234
  AND NAME = ?ExpectedName AND...

重点是如果另一个用户在此期间更改了记录,则删除应失败(不执行任何操作)。
有了这个更好的问题陈述,使用Entity Framework时有两种可能的解决方案。
1. 在Delete方法中,比较现有实例的预期属性值,如果相同,则删除。在这种情况下,Entity Framework将负责编写包含属性值的DELETE语句。
2. 编写一个存储过程,接受IDE和其他属性值,并执行该存储过程。

1
如果在对象的生命周期内从未修改过,或者要查找要删除的对象的查询暗示了您将验证的所有属性已经具有正确的值,那么这是一个完全有效的目标。 - Tim Lovell-Smith

3
var toDelete = new MyEntityModel{
    GUID = guid,
    //or ID = id, depending on the key
    };
Db.MyEntityModels.Attach(toDelete);
Db.MyEntityModels.DeleteObject(toDelete);
Db.SaveChanges();

如果您的密钥包含多个列,则需要提供所有值(例如GUID,columnX,columnY等)。

如果您喜欢花哨的东西,也可以在这里查看一个通用函数。


这是最好的方法(我称之为使用占位符对象),但它确实存在与Stuntz提出的并发问题相同的问题。 - dansan

2

使用Entity Framework 5时,可以使用Entity Framework扩展库。该库可在NuGet上获得。然后你可以编写类似以下的代码:

context.Users.Delete(u => u.Id == id);

它还可以用于批量删除。


这是一个令人难以置信的库!谢谢 - user4774787

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接