Entity framework core очистить таблицу
I'm deleting several items from a table using Entity Framework. There isn't a foreign key / parent object so I can't handle this with OnDeleteCascade.
Right now I'm doing this:
It works but the foreach bugs me. I'm using EF4 but I don't want to execute SQL. I just want to make sure I'm not missing anything - this is as good as it gets, right? I can abstract it with an extension method or helper, but somewhere we're still going to be doing a foreach, right?
50.7k 25 25 gold badges 121 121 silver badges 192 192 bronze badges24 Answers 24
EntityFramework 6 has made this a bit easier with .RemoveRange() .
Example:
29.5k 34 34 gold badges 124 124 silver badges 170 170 bronze badges For sure this answer is easier but performance wise it might not be great. Why? what this exatly doet is same as deleting it in foreach loop, it first fetches all the rows and then delete is one by one, only gain is for saving "DetectChanges will be called once before delete any entities and will not be called again" rest is same, try using tool to see sql generated. For a large enough range, try something like .Take(10000) and looping until RemoveRange(. ).Count() == 0. The problem is that RemoveRange input parameter is an IEnumerable so to perform delete it enumerates all the entities and run 1 DELETE query per entity. It seems a very not effective way. I checked it in SQL Profiler: RemoveRange command actually executes SELECTcommand and SaveChanges execute DELETE command for every single record that found after the first command SEPARATELY. In my opinion, the best way is to write relevant store procedure and execute it from EF.this is as good as it gets, right? I can abstract it with an extension method or helper, but somewhere we're still going to be doing a foreach, right?
Well, yes, except you can make it into a two-liner:
108k 27 27 gold badges 178 178 silver badges 220 220 bronze badges You are doing a ToList() which defeats the purpose. How is that any different from the original solution? I have problems since I only have Remove method in context object. This is definitely not a suitable solution when a million rows (or even a few hundred) are expected. However if we know for sure there will only be a few rows this solution is neat and works perfectly well. Yes, it would involve a few round trips to the DB, but in my opinion the lost abstraction involved in calling SQL directly outweighs the benefits. Entity Framework, as the name suggests, works best with data at entity level. Bulk data operations are best handled by good old stored procs. Performance-wise they are by far the best options and will beat any EF logic requiring a loop.I know it's quite late but in case someone needs a simple solution, the cool thing is you can also add the where clause with it:
Note: just tested with MSSQL2008.
Update:
The solution above won't work when EF generates sql statement with parameters, so here's the update for EF5:
It requires a little bit of reflection but works well.
If you don't want to execute SQL directly calling DeleteObject in a loop is the best you can do today.
However you can execute SQL and still make it completely general purpose via an extension method, using the approach I describe here.
Although that answer was for 3.5. For 4.0 I would probably use the new ExecuteStoreCommand API under the hood, instead of dropping down to the StoreConnection.
20.8k 3 3 gold badges 48 48 silver badges 49 49 bronze badges ExecuteStoreCommand is not a proper way.DeleteAllSubmit is working in linq to sql but not in entity framework. I want same option in entity framework. At this time (2020) this should not be the accepted answer. 6,233 5 5 gold badges 48 48 silver badges 64 64 bronze badges 6,032 2 2 gold badges 31 31 silver badges 41 41 bronze badges Has performance issues on large tables, not usable in my situation. @Tomas what kind of perfromance issued did you notice? How severe was the issue and on how Large was the Table? Anyone else can confirm that? It is really fast compare to the alternatives out there I cannot see Delete() function in my entities in EF6. I will strongly not recommend using this library. While it has Async versions of the methods, they are not true Async. It is just a wrapper around sync methods. You can get lots of unexpected issues by using this library in high load environment.Entity Framework Core
Summary:
Removes the given collection of entities from the context underlying the set with each entity being put into the Deleted state such that it will be deleted from the database when SaveChanges is called.
How can I quickly remove all rows in the table using Entity Framework?
I am currently using:
However, it takes a long time to execute.
Are there any alternatives?
1,154 1 1 gold badge 15 15 silver badges 26 26 bronze badges 3,619 3 3 gold badges 14 14 silver badges 15 15 bronze badges Reading the answers I wonder why none of these TRUNCATE adepts worry about foreign key constraints.23 Answers 23
For those that are googling this and ended up here like me, this is how you currently do it in EF5 and EF6:
Assuming context is a System.Data.Entity.DbContext
Warning: The following is only suitable for small tables (think < 1000 rows)
Here is a solution that uses entity framework (not SQL) to delete the rows, so it is not SQL Engine(R/DBM) specific.
This assumes that you're doing this for testing or some similar situation. Either
- The amount of data is small or
- The performance doesn't matter
Assuming this context:
For tidier code you can declare the following extension method:
Then the above becomes:
I recently used this approach to clean up my test database for each testcase run (it´s obviously faster than recreating the DB from scratch each time, though I didn´t check the form of the delete commands that were generated).
Why can it be slow?
- EF will get ALL the rows (VotingContext.Votes)
- and then will use their IDs (not sure exactly how, doesn't matter), to delete them.
So if you're working with serious amount of data you'll kill the SQL server process (it will consume all the memory) and same thing for the IIS process since EF will cache all the data same way as SQL server. Don't use this one if your table contains serious amount of data.
Great answer, speeded up my delete all rows code by a factor of 10! Note that I had to rename the Clear() static extension method to something like ClearDbSet() since I already had another Clear() static extension method defined elsewhere in my project. This does not reset the identity key. So if you clear 10 records, the next one will still be 11. I had to explicity call _context.SaveChanges() explicitly after RemoveRangeUsing SQL's TRUNCATE TABLE command will be the fastest as it operates on the table and not on individual rows.
Assuming dataDb is a DbContext (not an ObjectContext ), you can wrap it and use the method like this:
You can do that without Foreach
This will remove all rows
This avoids using any sql
I came across this question when I had to deal with a particular case: fully updating of content in a "leaf" table (no FKs pointing to it). This involved removing all rows and putting new rows information and it should be done transactionally (I do not want to end up with an empty table, if inserts fails for whatever reason).
I have tried the public static void Clear<T>(this DbSet<T> dbSet) approach, but new rows are not inserted. Another disadvante is that the whole process is slow, as rows are deleted one by one.
So, I have switched to TRUNCATE approach, since it is much faster and it is also ROLLBACKable. It also resets the identity.
Example using repository pattern:
Of course, as already mentioned, this solution cannot be used by tables referenced by foreign keys (TRUNCATE fails).
Как я могу быстро удалить все строки в таблице с помощью Entity Framework?
В настоящее время я использую:
Однако для выполнения требуется много времени.
Есть ли альтернативы?
Для тех, кто занимается поиском в Google и заканчивается здесь, как и я, так вы сейчас это делаете в EF5 и EF6:
Предполагаемый контекст - это System.Data.Entity.DbContext
Предупреждение: следующее подходит только для небольших таблиц (например, <1000 строк)
Вот решение, которое использует структуру сущностей (не SQL) для удаления строк, поэтому оно не является специфичным для SQL Engine (R/DBM).
Это предполагает, что вы делаете это для тестирования или какой-то подобной ситуации. Или
- Количество данных мало или
- Производительность не имеет значения
Предполагая этот контекст:
Для более простого кода вы можете объявить следующий метод расширения:
Тогда выше становится:
Недавно я использовал этот подход для очистки своей тестовой базы данных при каждом запуске тестового набора (это, очевидно, быстрее, чем воссоздание БД с нуля каждый раз, хотя я не проверял форму сгенерированных команд удаления).
Почему это может быть медленным?
- EF получит ВСЕ строки (VotingContext.Votes)
- а затем будет использовать их идентификаторы (не знаю точно, как, не имеет значения), чтобы удалить их.
Поэтому, если вы работаете с серьезным объемом данных, вы убьете процесс сервера SQL (он будет занимать всю память) и то же самое для процесса IIS, поскольку EF будет кэшировать все данные так же, как сервер SQL. Не используйте этот, если ваша таблица содержит серьезный объем данных.
Использование SQL TRUNCATE TABLE команда будет самой быстрой, поскольку она работает на таблице, а не на отдельных строках.
Предполагая, что dataDb является DbContext (а не ObjectContext ), вы можете его обернуть и использовать метод следующим образом:
Это позволяет избежать использования любого sql
Вы можете сделать это без Foreach
Это удалит все строки
Я сталкивался с этим вопросом, когда мне приходилось иметь дело с конкретным случаем: полным обновлением контента в "листовой" таблице (без ФК, указывающих на это). Это включало удаление всех строк и добавление информации о новых строках, и это должно быть сделано транзакционно (я не хочу заканчивать с пустой таблицей, если вставки терпят неудачу по любой причине).
Я пробовал public static void Clear<T>(this DbSet<T> dbSet) подход public static void Clear<T>(this DbSet<T> dbSet) , но новые строки не вставляются. Другим недостатком является то, что весь процесс идет медленно, так как строки удаляются одна за другой.
Итак, я переключился на подход TRUNCATE , так как он намного быстрее и также ROLLBACKable. Это также сбрасывает личность.
Пример использования шаблона хранилища:
Конечно, как уже упоминалось, это решение не может быть использовано в таблицах, на которые ссылаются внешние ключи (сбой TRUNCATE).
Как сказал Руди Виссер:
Использование команды SQL TRUNCATE TABLE будет самой быстрой, поскольку она работает в таблице, а не в отдельных строках.
dataDb.ExecuteStoreCommand( "TRUNCATE TABLE [Таблица]" );
Предполагая, что dataDb является DbContext (а не ObjectContext), вы можете его обернуть и использовать метод следующим образом:
var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter) dataDb).ObjectContext; objCtx.ExecuteStoreCommand( "TRUNCATE TABLE [Таблица]" );
Но вы должны быть осторожны, чтобы использовать после себя где-то только что созданный файл данных - иначе вы столкнетесь с конфликтами структуры организации. Внутри datacontext эти объекты все еще живы при использовании таблицы Truncate.
в мире реляционных баз данных позволяет удалять связанные данные из зависимой таблицы, при удалении данных из основной таблицы. В случае модели, которую мы использовали в предыдущих примерах (две связанные таблицы Customer и Order), при использовании каскадного удаления, удаление данных покупателя будет вести к удалению всех связанных с ним заказов. В SQL Server и T-SQL каскадное удаление реализовано в виде опций ON DELETE CASCADE и ON UPDATE CASCADE, которые указываются при объявлении внешнего ключа таблицы.
По умолчанию Code-First включает каскадное удаление для внешних ключей, не поддерживающих значение NULL, используя соответствующий SQL-код при создании таблицы. В предыдущей статье мы описали, как указать Code-First на то, что внешний ключ должен обязательно использоваться (т.е. поддерживать ограничение NOT NULL). Давайте вспомним, как это сделать:
Можно явно указать свойство внешнего ключа, тогда Code-First по умолчанию использует для него значение NOT NULL в базе данных. В примерах мы использовали внешние ключи CustomerId и UserId.
Если внешний ключ не указан в классе модели, тогда Code-First автоматически генерирует его, разрешая использовать NULL. Чтобы это изменить, можно использовать атрибут Required к навигационному свойству модели.
В этой форме используются две кнопки для удаления и сохранения данных. В коде обработчика Save_Click происходит создание произвольного объекта Customer с тремя связанными объектами Order, после чего эти данные вставляются в базу. В коде обработчика Delete_Click мы сначала извлекаем данные нужного заказчика из базы данных, а затем удаляем его. Обратите внимание, что здесь используется "жадная загрузка" (eager loading), т.к. мы вызываем метод Include(). Это означает, что помимо данных покупателя, будут извлечены все данные связанных с ним заказов. Фактически каскадное удаление в данном случае не нужно, т.к. мы уже извлекли все связанные заказы.
Модель данных на текущий момент выглядит следующим образом:
Запустите наш пример и откройте в браузере веб-форму CascadeDelete.aspx и щелкните по кнопке “Сохранить”. Entity Framework воссоздаст базу данных (если модель изменилась) и добавит новые данные в таблицы Customers и Orders. Чтобы в этом убедиться, используйте средства Visual Studio или SQL Server Management Studio для просмотра данных:
Нажмите на кнопку “Удалить”, чтобы убедиться, что данные покупателя и связанные с ним заказы удаляются корректно. При этом Entity Framework отправит четыре запроса DELETE базе данных (три для каждого заказа и один для покупателя). Давайте теперь отключим использование жадной загрузки и явно используем каскадное удаление. Ниже показан измененный код обработчика Delete_Click:
Здесь мы удалили вызов метода Include() и теперь Code-First не известно о связанных с покупателем заказов. В отличие от предыдущего примера, здесь Entity Framework отправит один запрос DELETE для удаления покупателя. При выполнении этого запроса сработает средство каскадного удаления и SQL Server найдет связанные заказы, удалит сначала их, а уже потом удалит покупателя.
Отключение каскадного удаления данных
Возможно вам понадобиться отключить использование каскадного удаления в базе данных. Как описывалось выше, чтобы сделать это, можно удалить явное определение первичного ключа из класса модели и положиться на автоматическую генерацию первичного ключа с помощью Code-First (при этом Code-First указывает поддержку NULL для этого ключа). Также можно воспользоваться средствами Fluent API для явного отключения каскадного удаления, если, например, требуется сохранить объявление первичного ключа в классе модели.
Важно помнить, что при отключении каскадного удаления в вашем приложении могут возникать ошибки, если вы не позаботитесь об извлечении связанных данных перед удалением, как мы это делали в первом примере с использованием “жадной загрузки”.
Отключить или включить каскадное удаление в Fluent API позволяет метод WillCascadeOnDelete(), которому передается логический параметр. Использование этого метода показано в примере ниже:
Если вы запустите приложение и попробуете удалить данные, используя второй пример обработчика Delete_Click, то возникнет исключение, показанное на рисунке ниже:
Как уже описывалось ранее, при удалении данных из родительской таблицы, необходимо позаботиться об удалении данных из производной таблицы. Мы забыли извлечь данные связанных заказов из таблицы Orders и поэтому SQL Server вернул ошибку при попытке удаления данных только покупателя. Если вы теперь включите “жадную загрузку” с помощью метода Include() в обработчике Delete_Click, то эта ошибка исчезнет, но возникнет новая – как описывалось выше, в этом случае Code-First отправит четыре запроса на удаление и при удалении первого заказа Code-First установит для свойства Order.Customer значение NULL, а т.к. наша модель содержит внешний ключ, который не может иметь значение NULL возникнет ошибка.
Из этого описания можно сделать вывод, что для данного примера отключение каскадного удаления нельзя применить, но тогда возникает вопрос, зачем вообще отменять каскадное удаление? По своему опыту скажу, что отключение каскадного удаления используется в основном при получении циклической ссылки между таблицами в сложных базах данных. Такая ссылка может возникнуть, если между несколькими таблицами используется отношение “родительская-дочерняя” и последняя зависимая таблица неожиданно ссылается на одну из родительских таблиц. Проблема циклических ссылок проявляется не только при удалении данных, а также при их обновлении (операция UPDATE в T-SQL).
Также отключение каскадного удаления требуется для таблиц, которые определяют несколько отношений между собой. Некоторые базы данных (в том числе SQL Server) не поддерживают несколько отношений, которые определяют каскадное удаление, указываемое на одной таблице.
Читайте также: