如何用EF6删除1000行?

我正在使用entity framework6。

我有一个名为Tests的testing信息表。 我从这个表中删除行首先得到一个testing列表,做一个删除每个然后一个提交。

var testList = _testService.GetTests(1, userId).ToList(); testList.ForEach(_obj => _uow.Tests.Delete(_obj)); _uow.Commit(); 

我有另一个问题的信息称为问题表。 我想这样做,但在这个表中有超过1000行。 如果我把它们全部列出来,然后做1000个删除,这将不是非常有效。

这个问题的删除不经常发生。 有没有人有一个build议,我怎么能做到这一点。 我应该做1000次删除。 使用EF做这种事情是正常的吗?

EF 6据我所知在你的DbContext中引入了.RemoveRange()选项。 所以简而言之,你可以做如下的事情:

 var db = new MyDbContext(); var itemsToDelete = db.MyTable.Where(x=>!x.active); db.MyTable.RemoveRange(itemsToDelete); db.SaveChanges(); 

所以,而不必做任何types的foreach ,你可以利用这种新的扩展方法。 使用Unit Of Work上下文,您可以重载Delete方法,该方法使用IEnumerable(?*)而不是像当前方法那样的单个Test对象。 这个新的重载应该调用RemoveRange()上的RemoveRange RemoveRange()函数。

?* – 取决于GetTests()返回的内容,但是我认为IEnumerable<>包含了IList<>IQueryable<>

编辑

几个意见。 首先,在发出RemoveRange之前,我不会调用.ToList() ,因为您不想实际将项目提取到您的服务。 这应该有助于减less一些执行时间。 其次,你说得对,你仍然会发出1000条删除语句。 但是,性能提升来自于不在EF中调用您要从DbSet中移除的每个单独项目的DbSet 。 来自MSDN杂志 :

AddRange和RemoveRange如前所述,AddRange和RemoveRange是来自社区成员Zorrilla的贡献。 每种方法都以一个单一的实体types的枚举为参数。 在共享DbTransactions部分的第一个代码示例中,当我传入一个Casino实例数组时,我使用了AddRange:

context.Casinos.AddRange(new [] {casino1,casino2}); 这些方法的执行速度比每次添加或删除单个对象要快得多,因为默认情况下,Entity Framework会在每个“添加和删除”方法中调用DetectChanges。 使用Range方法,您可以处理多个对象,而仅调用一次DetectChanges,从而显着提高性能。 我已经用5,50,500,5,000甚至50,000个对象testing过了,至less在我的情况下,对数组的大小没有限制,而且速度非常快! 请记住,这种改进只与获取上下文才能对对象起作用有关,对SaveChanges没有任何影响。 调用SaveChanges一次只能执行一个数据库命令。 因此,尽pipe您可以快速将5万个对象添加到上下文中,但在调用SaveChanges时仍然可以单独执行50,000个插入命令 – 可能不是您想要在真实系统中执行的操作。

另一方面,长时间讨论了如何实现对批量操作的支持,而不需要通过EF(bit.ly/16tMHw4)来跟踪对象,而批量操作则可以通过一次调用将多个命令一起发送到数据库(bit.ly/PegT17)。 这两个function都没有成为最初的EF6版本,但都是重要的,将来的版本。

如果你真的只想发出一个单一的数据库命令,那么使用原始SQL语句的存储过程将是实现的方法,因为EntityFramework不支持批量事务。 但是,与在foreach循环中调用Remove()相比,使用RemoveRangeAddRange项目(特别是,如您所说的那样,很less出现)会为您节省大量的时间。

内置在Entity Framework .RemoveRange()方法中,仍然获取内存上的条目,并发出X删除循环虽然所有这些。

如果你不想写任何删除的SQL, 特别是在select要删除的实体是复杂的时候

entity framework扩展库提供了只发布一个命令的批量删除更新方法。

 //Deleting context.Users .Where(u => u.FirstName == "firstname") .Delete(); 

目前的entity framework的限制是,为了更新或删除一个实体,您必须先将其检索到内存中。 现在在大多数情况下,这很好。 然而,有些seneriosperformance会受到影响。 另外,对于单次删除,必须先检索该对象,然后才能删除需要对数据库进行两次调用的对象。 批量更新和删除不需要在修改实体之前检索和加载实体。

我用EF6和Sql Server Profiler做了一些testing

使用.RemoveRange()

它首先获取所有logging从数据库中删除

exec sp_executesql N'SELECT [Extent1]。[Id] AS [Id],[Extent1]。[IdOrder] AS [IdOrder],[Extent1]。[Name] AS [Name],[Extent1]。[Partita] AS [ [MyTable] AS [Extent1] WHERE [Extent1]。[IdOrder] = @ p__linq__0',N'@ p__linq__0 varchar(8000)',@ p__linq__0 ='0cb41f32-7ccb-426a-a159- b85a4ff64c29'

然后它将N删除命令激活到数据库

exec sp_executesql N'DELETE [dbo]。[MyTable] WHERE([Id] = @ 0)',N'@ 0 varchar(50)',@ 0 ='ffea29aa-8ba5-4ac9-871b-3f5979180006'

X 1000次

这发生了也使用和IQueriable

使用entity framework扩展库

它只向数据库发出一个命令

exec sp_executesql N'DELETE [dbo]。[MyTable] FROM [dbo]。[MyTable] AS j0 INNER JOIN(SELECT 1 AS [C1],[Extent1]。[Id] AS [Id] FROM [dbo]。[MyTable ] AS [Extent1] WHERE [Extent1]。[IdOrder] = @ p__linq__0)AS j1 ON(j0。[Id] = j1。[Id])',N'@ p__linq__0 nvarchar(36)',@ p__linq__0 = N' 0cb41f32-7ccb-426A-A159-b85a4ff64c29'