如何通过实体框架按ID删除对象


105

在我看来,在使用如下所示的实体框架删除对象之前,我必须先检索一个对象

var customer = context.Customers.First(c => c.Id == 1);

context.DeleteObject(customer);

context.Savechanges();

所以我需要打两次数据库。有没有更简单的方法?


j.mp/f0x0Bh是您的答案。这是一个很好的和做的一般方法
BritishDeveloper

Answers:


93

在Entity Framework 6中,删除动作为Remove。这是一个例子

Customer customer = new Customer () { Id = id };
context.Customers.Attach(customer);
context.Customers.Remove(customer);
context.SaveChanges();

16
为什么Attach呢 为什么不只是RemoveSaveChanges
runeks

3
您必须将实体附加到上下文中,因为如果不这样做,则在删除时会收到错误消息。EF只能在这种情况下删除实体
Pierre-Luc,

3
根据该手册,@ runeks实体必须在上下文中存在,然后才能执行Remove操作。看到这里docs.microsoft.com/en-us/dotnet/api/…–
dwkd

1
我没有使用
Attach

58

与@Nix相同,只需要进行少量更改即可进行强类型输入:

如果您不想查询它,只需创建一个实体,然后将其删除。

                Customer customer = new Customer () { Id = id };
                context.Customers.Attach(customer);
                context.Customers.DeleteObject(customer);
                context.SaveChanges();

7
这不是很完美,因为如果缺少对象,它将引发异常:“ DbUpdateConcurrencyException:存储更新,插入或删除语句影响了意外的行数(0)。” 我希望它像DELETE语句那样忽略它。
2015年

抱歉,这导致不需要验证并且总是需要进行验证!
Hamed Zakery Miab

32

这里有类似的问题。

有了Entity Framework,就有了EntityFramework-Plus(扩展库)。
在NuGet上可用。然后,您可以编写如下内容:

// DELETE all users which has been inactive for 2 years
ctx.Users.Where(x => x.LastLoginDate < DateTime.Now.AddYears(-2))
     .Delete();

这对于批量删除也很有用。


36
这没有理由说明它现在还不是核心EF库的一部分。
nathanchere 2013年

1
@FerretallicA-同意。
acarlon

2
此方法已过时:context.Users.Where(user => user.Id == id).Delete();
曼努埃尔

由于错误“ DELETE语句当前不支持FROM子句”,因此它不适用于Azure SQL DataWarehouse。但是像Jonik的答案中的原始SQL一样有效。
Michael Freidgeim

1
是否需要context.SaveChanges()?
Tomas Kubes

23

如果您不想查询它,只需创建一个实体,然后将其删除。

Customer customer  = new Customer() {  Id = 1   } ; 
context.AttachTo("Customers", customer);
context.DeleteObject(customer);
context.Savechanges();

6

我在我的一个项目中使用以下代码:

    using (var _context = new DBContext(new DbContextOptions<DBContext>()))
    {
        try
        {
            _context.MyItems.Remove(new MyItem() { MyItemId = id });
            await _context.SaveChangesAsync();
        }
        catch (Exception ex)
        {
            if (!_context.MyItems.Any(i => i.MyItemId == id))
            {
                return NotFound();
            }
            else
            {
                throw ex;
            }
        }
    }

这样,只有在尝试删除具有指定ID的项目时发生异常时,它才会对数据库进行两次查询。然后,如果找不到该项目,它将返回一条有意义的消息;否则,它只会抛出异常(您可以针对不同的异常类型使用不同的catch块,通过使用if块等添加更多自定义检查,从而以更适合您的情况的方式处理此异常)。

[我正在带有Entity Framework Core的MVC .Net Core / .Net Core项目中使用此代码。]


2

我想原始SQL查询是最快的方法

public void DeleteCustomer(int id)
{
   using (var context = new Context())
   {
      const string query = "DELETE FROM [dbo].[Customers] WHERE [id]={0}";
      var rows = context.Database.ExecuteSqlCommand(query,id);
      // rows >= 1 - count of deleted rows,
      // rows = 0 - nothing to delete.
   }
}

19
这无法达到在EF中使用强类型对象函数的目的。
LawMan

4
这损害了EF身份现金。此后,EF仍将返回您已删除的实体。
epox

1
当其他解决方案不起作用时,它可与Azure SQL DataWarehouse一起使用。
Michael Freidgeim

1
如果执行此操作,则可能不使用ORM。我想这会损害EF缓存。
Storm Muller

这种样式容易受到SQL注入攻击的攻击。在此特定示例中,您受到保护,因为该变量是整数,但切勿将此模式与字符串变量一起使用。
塞勒姆

2

dwkd的答案主要是在Entity Framework核心中为我工作的,除非我看到以下异常:

InvalidOperationException:无法跟踪实体类型“ Customer”的实例,因为已经跟踪了另一个具有相同“ {'Id”}键值的实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。考虑使用“ DbContextOptionsBuilder.EnableSensitiveDataLogging”来查看冲突的键值。

为避免异常,我更新了代码:

Customer customer = context.Customers.Local.First(c => c.Id == id);
if (customer == null) {
    customer = new Customer () { Id = id };
    context.Customers.Attach(customer);
}
context.Customers.Remove(customer);
context.SaveChanges();

1

较小的版本(与以前的版本相比):

var customer = context.Find(id);
context.Delete(customer);
context.SaveChanges();

请提供此代码段的一些上下文,并可能对它比过去十年留下的其他答案有更好的解释。
miken32

1

该答案实际上取自Scott Allen的名为ASP.NET MVC 5基础知识的课程。我想分享一下,因为它比这里的任何答案都更简单,更直观。还要注意,根据Scott Allen和我所做的其他培训,find方法是从数据库中检索资源的一种优化方法,如果已经检索到该资源,则可以使用缓存。在此代码中,集合是指对象的DBSet。对象可以是任何通用对象类型。

        var object = context.collection.Find(id);  
        context.collection.Remove(object);
        context.SaveChanges();
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.