Как удалить объект по id с помощью entity framework


104

Мне кажется, что я должен получить объект, прежде чем удалять его с помощью структуры сущностей, как показано ниже

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

context.DeleteObject(customer);

context.Savechanges();

Поэтому мне нужно дважды попасть в базу данных. Есть способ попроще?


j.mp/f0x0Bh - ваш ответ. Это хороший и общий способ сделать это
BritishDeveloper

Ответы:


95

В Entity Framework 6 действие удаления есть Remove. Вот пример

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

16
Почему Attach? Почему не просто Removeи SaveChanges?
runeks

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();

Это также полезно для массового удаления.


37
Это противоречит той причине, что на данный момент это не часть основной библиотеки EF.
nathanchere

1
@FerretallicA - согласился.
acarlon

2
этот метод устарел использовать: context.Users.Where (user => user.Id == id) .Delete ();
Мануэль

Он не работает с хранилищем данных SQL Azure из-за ошибки «Предложение FROM в настоящее время не поддерживается в операторе DELETE». Но сырье SQL , как и в Jonik в ответных работах.
Майкл Фрейджейм

1
Нужен ли context.SaveChanges ()?
Tomas Kubes

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

Таким образом, он будет запрашивать базу данных дважды, только если возникает исключение при попытке удалить элемент с указанным идентификатором. Затем, если элемент не найден, возвращается содержательное сообщение; в противном случае он просто возвращает исключение (вы можете справиться с этим способом, более подходящим для вашего случая, используя разные блоки catch для разных типов исключений, добавьте дополнительные пользовательские проверки, используя блоки if и т. д.).

[Я использую этот код в проекте 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, 04

4
Это ставит под угрозу идентификационные данные EF. После этого EF все равно вернет вам удаленную сущность.
epox

1
Он работает с хранилищем данных SQL Azure, а другие решения - нет.
Майкл Фрейджейм

1
Если вы делаете это, вы также можете не использовать ORM. Я предполагаю, что это скомпрометирует кеш EF.
Шторм Мюллер

Этот стиль уязвим для атак SQL Injection. В этом конкретном примере вы защищены, потому что переменная является целым числом, но никогда не используйте этот шаблон со строковой переменной.
thelem

2

Ответ 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();

2

Меньшая версия (по сравнению с предыдущими):

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

Пожалуйста, предоставьте некоторый контекст для этого фрагмента кода и, возможно, объясните, что он делает лучше, чем другие ответы, оставшиеся за последнее десятилетие.
miken32

1

Этот ответ фактически взят из курса Скотта Аллена под названием «Основы ASP.NET MVC 5». Я думал, что поделюсь, потому что я думаю, что это немного проще и интуитивно понятнее, чем любой из ответов здесь уже. Также обратите внимание, согласно Скотту Аллену и другим моим тренингам, метод find - это оптимизированный способ получения ресурса из базы данных, который может использовать кеширование, если он уже был получен. В этом коде коллекция относится к DBSet объектов. Объект может быть любым универсальным типом объекта.

        var object = context.collection.Find(id);  
        context.collection.Remove(object);
        context.SaveChanges();
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.