Подтвердить что ты не робот

Как удалить 1000 строк с помощью EF6?

Я использую Entity Framework 6.

У меня есть таблица с тестовой информацией под названием Tests. Я удаляю строк из этой таблицы, сначала получив список тестов, делая delete для каждого, а затем commit.

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

У меня есть другая таблица с информацией о вопросе, которая называется "Вопросы". Я хотел бы сделать то же самое, но есть более 1000 строк в этом Таблица. Если я перечислил их все, а затем сделаю 1000 удалений, не очень эффективны.

Это исключение вопросов происходит нечасто. Есть ли у кого-то есть предложение, как я могу это сделать. Я должен делать 1,000 удаляет. Нормально ли это делать с помощью EF?

4b9b3361

Ответ 1

EF 6, насколько я знаю, ввел параметр .RemoveRange() в свой DbContext. Короче говоря, вы можете сделать что-то вроде следующего:

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

Поэтому вместо того, чтобы делать любой тип foreach, вы можете использовать этот новый метод расширения. С вашим контекстом Unit Of Work вы можете перегрузить ваш метод Delete, который принимает IEnumerable (? *) Вместо одного объекта Test, такого как ваш текущий метод. Эта новая перегрузка должна вызывать функцию RemoveRange() в DbContext.

? * - Это зависит от того, что возвращает GetTests(), но я думаю, что IEnumerable<> охватывает как IList<>, так и IQueryable<>

Edit

Несколько комментариев. Во-первых, я бы не назвал .ToList() перед выпуском RemoveRange, так как вы не хотите, чтобы вы действительно загружали элементы в свою службу. Это должно помочь сократить время выполнения. Во-вторых, вы правы, как бы то ни было, что вы все равно будете выдавать 1000 операторов удаления. Однако прирост производительности обусловлен тем, что вы не вызываете ChangeTracker в EF для каждого отдельного элемента, который вы удаляете из DbSet. Из журнала MSDN:

AddRange и RemoveRange Как упоминалось ранее, AddRange и RemoveRange - это вклад членов сообщества Zorrilla. каждый метод принимает в качестве своего параметра перечислимый тип одного объекта. В первом примере кода в разделе совместного использования DbTransactions я использовал AddRange, когда я передал массив экземпляров казино:

context.Casinos.AddRange(новый [] {casino1, casino2}); Эти методы выполняются намного быстрее, чем добавление или удаление одного объекта за раз потому что по умолчанию Entity Framework вызывает DetectChanges в каждом добавлении и Удалить. С помощью методов Range вы можете обрабатывать несколько объекты, в то время как DetectChanges вызывается только один раз, улучшая производительность драматически. Ive проверил это, используя пять, 50, 500, 5000 и даже 50 000 объектов и, по крайней мере, в моем сценарии, нет ограничений для размер массива - и его впечатляюще быстро! Имейте в виду, что это улучшение имеет значение только для того, чтобы контекст воздействовал на объектов и не имеет отношения к SaveChanges. Вызов SaveChanges по-прежнему выполняет только одну команду базы данных за раз. Поэтому, пока вы можете быстро добавьте 50 000 объектов в контекст, вы все равно получите 50 000 вложений команды, выполняемые индивидуально, когда вы вызываете SaveChanges, возможно, не то, что вы хотите сделать в реальной системе.

С другой стороны, были длительные дискуссии о реализация поддержки массовых операций без необходимости отслеживать EF (бит .ly/16tMHw4) и для пакетных операций для включения отправка нескольких команд вместе в одном вызове в базу данных (Bit.ly/PegT17). Ни одна из функций не попала в исходную версию EF6, но оба они важны и предназначены для будущего выпуска.

Если вы действительно хотите только выдавать одну команду базы данных, либо хранимая процедура использования необработанных SQL-операторов будет способом, так как EntityFramework не поддерживает массовые транзакции. Однако использование элементов RemoveRange и AddRange (особенно если, как вы сказали, нечасты), сэкономит вам много времени по сравнению с вызовом Remove() в цикле foreach.

Ответ 2

Встроенный метод Entity Framework .RemoveRange(), по-прежнему выбирает записи в памяти и выпускает X, удаляет цикл, хотя все они.

Если вы не хотите писать Any SQL for Deletion, особенно при выборе того, какие объекты для удаления сложны

Расширенная библиотека расширенных возможностей Entity Framework предлагает пакетное удаление-обновление методов, выдающих только одну команду.

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

Текущие ограничения Entity Framework заключаются в том, что для обновления или удаления объекта, который вы должны сначала извлечь в память. Сейчас в большинстве сценариев это прекрасно. Однако есть некоторые сенероны, в которых производительность будет страдать. Кроме того, для одиночных удалений объект должен быть извлечен до его удаления, требуя двух вызовов в базе данных. Пакетное обновление и удаление исключает необходимость извлечения и загрузки объекта перед его модификацией.

Ответ 3

Я провел несколько тестов с использованием EF6 и Sql Server Profiler

Использование .RemoveRange()

Сначала он извлекает всю запись для удаления из базы данных

exec sp_executesql N'SELECT     [Extent1]. [Id] AS [Id],     [Extent1]. [IdOrder] AS [IdOrder],     [Extent1]. [Name] AS [Name],     [Extent1]. [Partita] AS [Partita],     FROM [dbo]. [MyTable] AS [Extent1]     WHERE [Extent1]. [IdOrder] = @p__linq__0 ', N' @p__linq__0 VARCHAR (8000)", @p__linq__0 = '0cb41f32-7ccb-426а-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-426а-A159-b85a4ff64c29'