Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delete entities without loading them into memory

In Entity Framework Core I have the following Entity:

public class File {
  public Int32 Id { get; set; }
  public Byte[] Content { get; set; }
  public String Name { get; set; }
}

And I have a list of files ids which I need to delete:

List<Int32> ids = new List<Int32> { 4, 6, 8 }; // Ids example

How can I delete the 3 files without loading each file Content property?

_context.Files.Remove(??);

I do not want to load each file Content property as it is big in size.

like image 674
Miguel Moura Avatar asked Jan 25 '18 12:01

Miguel Moura


3 Answers

If you are sure the all Ids exist in the database and context does not contain (is not tracking) other entities with the same keys, you can use simple fake (stub) entities:

_context.RemoveRange(ids.Select(id => new File { Id = id })); 

To avoid problem with non existing ids, you can get the existing ids from the database:

var existingIds = _context.Files.Where(f => ids.Contains(f.Id)).Select(f => f.Id).ToList();  _context.RemoveRange(existingIds.Select(id => new File { Id = id })); 

To avoid tracking entity problem, you can use the FindTracked custom extension method from my answer to Delete loaded and unloaded objects by ID in EntityFrameworkCore and combine it with any of the above.

var existingIds = _context.Files.Where(f => ids.Contains(f.Id)).Select(f => f.Id).ToList();  _context.RemoveRange(     existingIds.Select(id => _context.FindTracked(id) ?? new File { Id = id })); 
like image 100
Ivan Stoev Avatar answered Sep 30 '22 09:09

Ivan Stoev


Entity tracking can work manually and without any database call, so long as you can uniquely identify the entity.

What you are after is documented here.

var entity = new EntityModel {    Id = yourId };  var entry = context.Entry(entity); entry.State = EntityState.Deleted; context.SaveChanges(); 

Which is the same as ...

var entity = new EntityModel {    Id = yourId };  var entry = context.Entry(entity); context.Remove(entry); context.SaveChanges(); 
like image 30
Ablue Avatar answered Sep 30 '22 11:09

Ablue


Install Z.EntityFramework.Extensions or Z.EntityFramework.Extensions.EFCore package according to your dotnet version.

Then use DeleteFromQuery() or DeleteFromQueryAsync() method after your query.

await _dbContext.MyTable.Where(w => w.TypeId == 5).DeleteFromQueryAsync();

DeleteFromQuery gives you access to directly execute a DELETE statement in the database and provide a HUGE performance improvement without select and load objects.

Performance Comparisons :

Operations : 1,000 Entitie - 2,000 Entities - 5,000 Entities

SaveChange : 1,000 ms - 2,000 ms - 5,000 ms

DeleteFromQuery : 1 ms - 1 ms - 1 ms

like image 30
M Komaei Avatar answered Sep 30 '22 09:09

M Komaei