如何使用实体框架通过 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
?为什么不只是Remove
和SaveChanges
?
您必须在上下文中附加您的实体,因为如果您不这样做,您将在删除时收到错误消息。 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 删除对象的主要内容,如果未能解决你的问题,请参考以下文章