Як видалити об'єкт за ідентифікатором з фреймворком сутності


105

Мені здається, що я повинен отримати об'єкт, перш ніж видалити його за допомогою структури сутностей, як показано нижче

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

context.DeleteObject(customer);

context.Savechanges();

Тому мені потрібно двічі потрапити в базу даних. Чи є простіший спосіб?


j.mp/f0x0Bh - це ваша відповідь. Це приємний і загальний спосіб зробити це
BritishDeveloper

Відповіді:


93

В Entity Framework 6 дія видалення є Remove. Ось приклад

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

16
Чому Attach? Чому б не просто Removeі SaveChanges?
рунекс

3
Ви повинні приєднати свою організацію до контексту, оскільки якщо цього не зробити, ви отримаєте помилку під час видалення. EF може видаляти суб’єкти лише в цьому контексті
П'єр-Люк

3
@runeks відповідно до посібника, об'єкт повинен існувати в контексті, перш ніж операція "Видалення" може бути виконана. Дивіться тут docs.microsoft.com/en-us/dotnet/api/…
dwkd

1
Я не використовував вкладення, і це прокидається чудово
ІЛІАС М. ДОЛАПО

58

Те саме, що @Nix з невеликою зміною, яку слід набрати:

Якщо ви не хочете запитувати його, просто створіть сутність і видаліть її.

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

7
Не є ідеальним, оскільки він кидає виняток, якщо об'єкт відсутній: "DbUpdateConcurrencyException: Зберігання операції оновлення, вставки або видалення вплинуло на несподіване число рядків (0)." Я хотів би, щоб це ігнорувало, як і DELETE.
Данк

Вибачте, це викликає перевірку, яка не потрібна і очікується завжди!
Hamed Zakery Miab

32

Подібне запитання тут .

З Entity Framework існує EntityFramework-Plus (бібліотека розширень).
Доступно на NuGet. Тоді ви можете написати щось на кшталт:

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

Він також корисний для масових видалень.


36
Це не викликає причини, що до теперішнього часу це не є частиною основної бібліотеки EF.
натанчере

1
@FerretallicA - погодився.
акарлон

2
цей метод є застарілим використанням: context.Users.Where (user => user.Id == id) .Delete ();
Мануель

Він не працює з Azure SQL DataWarehouse через помилку "Запропорення FROM на даний момент не підтримується в операторі DELETE." Але сирий SQL, як у відповіді Джоніка, працює.
Майкл Фрейджім

1
Чи потрібен контекст. Зберегти зміни ()?
Томаш Кубес

23

Якщо ви не хочете запитувати його, просто створіть сутність, а потім видаліть її.

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

6

Я використовую такий код в одному зі своїх проектів:

    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;
            }
        }
    }

Таким чином, він буде запитувати базу даних двічі, лише якщо виняток виникає при спробі видалити елемент із вказаним ідентифікатором. Потім, якщо елемент не знайдено, він повертає змістовне повідомлення; в іншому випадку він просто відкидає виняток назад (ви можете впоратись із цим способом, який більше відповідає вашому випадку, використовуючи різні блоки вилову для різних типів винятків, додайте більше спеціальних перевірок, використовуючи, якщо блоки тощо).

[Я використовую цей код у проекті MVC .Net Core / .Net Core з Entity Framework Core.]


2

Я думаю, що швидкий запит на 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.
   }
}

19
Це перешкоджає використанню сильно набраної функціональності об'єкта в EF.
LawMan

4
Це компрометує готівкові гроші з посвідченням EF. Після цього EF все одно поверне вам вашу видалену сутність.
епокс

1
Він працює з Azure SQL DataWarehouse, коли інших рішень немає.
Майкл Фрейджім

1
Якщо ви робите це, ви можете також не використовувати ORM. Я думаю, що це призведе до компрометації кешу EF.
Штурм Мюллер

Цей стиль вразливий до атак SQL Injection. У цьому конкретному прикладі ви захищені, оскільки змінна є цілим числом, але ніколи не використовуйте цей шаблон із змінною рядка.
thelem

2

Відповідь dwkd в основному працювала для мене в ядрі Entity Framework, за винятком випадків, коли я бачив цей виняток:

InvalidOperationException: Екземпляр типу сутності "Customer" неможливо відстежити, оскільки інший екземпляр із тим же значенням ключа для {'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();

1

Менша версія (порівняно з попередньою):

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

Укажіть, будь ласка, деякий контекст цього фрагмента коду та, можливо, пояснення того, що він робить краще, ніж інші відповіді, залишені за останнє десятиліття.
miken32

1

Ця відповідь насправді взята з курсу Скотта Аллена під назвою ASP.NET MVC 5 Основи. Я думав, що поділюсь, тому що я думаю, що це трохи простіше та інтуїтивніше, ніж будь-яка відповідь тут уже. Також зауважте, згідно зі Скоттом Алленом та іншими тренінгами, які я проводив, метод пошуку - це оптимізований спосіб отримати ресурс із бази даних, який може використовувати кешування, якщо він уже був знайдений. У цьому коді колекція посилається на DBSet об'єктів. Об'єктом може бути будь-який загальний тип об'єкта.

        var object = context.collection.Find(id);  
        context.collection.Remove(object);
        context.SaveChanges();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.