如何使用实体框架通过 id 删除对象

Posted

技术标签:

【中文标题】如何使用实体框架通过 id 删除对象【英文标题】:How to delete an object by id with entity framework 【发布时间】:2011-01-29 02:38:36 【问题描述】:

在我看来,我必须先检索一个对象,然后才能使用下面的实体框架删除它

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

context.DeleteObject(customer);

context.Savechanges();

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

【问题讨论】:

j.mp/f0x0Bh 是您的答案。这是一种很好的通用方式 【参考方案1】:

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

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

【讨论】:

为什么是Attach?为什么不只是RemoveSaveChanges 您必须在上下文中附加您的实体,因为如果您不这样做,您将在删除时收到错误消息。 EF 只能删除此上下文中的实体 @runeks 根据手册,实体必须存在于上下文中,然后才能执行删除操作。见这里docs.microsoft.com/en-us/dotnet/api/… 我没用attach,很好用 人们可能会混淆 Entity Framework Core 和 Entity Framework 之间的 Remove 用法。确实,对于实体框架,Remove 方法需要在Attach 方法之后调用,正如@Pierre-Luc 所提到的。但是,对于EFCore,Remove 方法将开始跟踪实体是否已删除。【参考方案2】:

与@Nix 相同,只是对强类型稍作改动:

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

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

【讨论】:

不完美,因为如果缺少对象会引发异常:“DbUpdateConcurrencyException:存储更新、插入或删除语句影响了意外的行数 (0)。”我希望它忽略这一点,就像 DELETE 语句一样。 抱歉,这会导致不需要和预期的验证!【参考方案3】:

类似问题here。

使用实体框架有EntityFramework-Plus(扩展库)。 在 NuGet 上可用。然后你可以这样写:

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

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

【讨论】:

它现在还不是核心 EF 库的一部分。 @FerretallicA - 同意。 这个方法已经过时了:context.Users.Where(user=> user.Id == id).Delete(); 它不适用于 Azure SQL DataWarehouse,因为错误“A FROM 子句当前在 DELETE 语句中不受支持。”。但是 Jonik 的 answer 中的原始 SQL 可以正常工作。 是否需要 context.SaveChanges()?【参考方案4】:

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

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

【讨论】:

【参考方案5】:

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

    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 项目中使用此代码。]

【讨论】:

这是理想的解决方案。【参考方案6】:

这个答案实际上取自 Scott Allen 的名为 ASP.NET MVC 5 Fundamentals 的课程。我想我会分享,因为我认为它比这里的任何答案都稍微简单和直观。另请注意,根据 Scott Allen 和我完成的其他培训,find 方法是一种从数据库中检索资源的优化方法,如果它已经被检索到,则可以使用缓存。在此代码中,collection 指的是对象的 DBSet。对象可以是任何通用对象类型。

        var object = context.collection.Find(id);  
        context.collection.Remove(object);
        context.SaveChanges();

【讨论】:

对象可能为空。如果它为空, .Remove(object);会抛出异常。【参考方案7】:

dwkd 的回答主要在 Entity Framework 核心中对我有用,除非我看到这个异常:

InvalidOperationException:实体类型“客户”的实例不能 被跟踪,因为另一个实例具有相同的 '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();

【讨论】:

相信你想用FirstOrDefault?【参考方案8】:

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

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

【讨论】:

请为这段代码 sn-p 提供一些上下文,或许还可以解释一下它比过去十年留下的其他答案做得更好的地方。【参考方案9】:

我认为原始 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.
   

【讨论】:

这违背了在 EF 中使用强类型对象功能的目的。 这会损害 EF 身份现金。在此 EF 之后仍会将您删除的实体返回给您。 它适用于 Azure SQL DataWarehouse,而其他解决方案不适用。 如果你这样做,你最好不要使用 ORM。我想这会损害 EF 缓存。 这种风格容易受到 SQL 注入攻击。在这个特定示例中,您受到保护,因为变量是一个整数,但永远不要将此模式与字符串变量一起使用。

以上是关于如何使用实体框架通过 id 删除对象的主要内容,如果未能解决你的问题,请参考以下文章

如何首先使用实体​​框架 5 代码删除具有导航属性的对象?

如何使用实体框架检索插入实体的 ID? [关闭]

如何从实体框架 6 中的 Auditlog 实体获取 id

如何在实体框架中循环创建和删除记录

如何在原始查询中使用实体框架事务?

从实体框架中删除一条记录?