0

I have seen and I am sure used this technique with EF Core to remove a record by creating a stub object to save a trip to the db, but using this method does not ever send a delete to the db. Does anyone know why?

public void DeleteById(int blogPostId)
{
    // Does not work
    // Use Stub to save extra db trip
    /*
    var blogPost = new BlogPost { Id = blogPostId };
    _context.Entry(blogPost).State = EntityState.Deleted;
    _context.BlogPosts.Remove(blogPost);
    _context.SaveChanges(); 
    */

    // Works
    var blogPost = _context.BlogPosts.Find(blogPostId);
    _context.Entry(blogPost).State = EntityState.Deleted;
    _context.BlogPosts.Remove(blogPost);
    _context.SaveChanges(); 
}

As an additional question, what is difference between using remove directly on the context or on the DbSet as both work fine?

    _context.Remove(blogPost);
    _context.BlogPosts.Remove(blogPost);

If I change the code to the below:

public void DeleteById(int blogPostId)
{
    // Does not work
    // Use Stub to save extra db trip

    var blogPost = new BlogPost { Id = blogPostId };
    //_context.Entry(blogPost).State = EntityState.Deleted;
    _context.BlogPosts.Remove(blogPost);
    _context.SaveChanges();


    // Works
    //var blogPost = _context.BlogPosts.Find(blogPostId);
    //_context.Entry(blogPost).State = EntityState.Deleted;
    //_context.BlogPosts.Remove(blogPost);
    //_context.SaveChanges(); 
}

I get the error below:

  An unhandled exception has occurred while executing the request.

System.InvalidOperationException: The instance of entity type 'BlogPost' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.

Tig2810
  • 149
  • 4
  • 10
  • You don't need to set the `State` on the Entry. Calling `_context.Remove(blogPost)` will add the entity to the tracking changes mechanism and set its (and related entities) state to deleted. – jpgrassi May 12 '19 at 20:33
  • As per your first example not working, it's strange because it should be working. Is that your real code, or just a simplification of it? – jpgrassi May 12 '19 at 20:41
  • It's the full code as it's a test to demonstrate the issue. If I do not set the state to deleted, I get the error I updated in the post. – Tig2810 May 13 '19 at 09:58

1 Answers1

0

THIS ANWSER IS A COPY FROM HERE

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 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 }));
  • That's an answer to a different question. – Tig2810 May 14 '19 at 18:14
  • Tig2810 No it's the exact answer. He want's to delete with EF Core without the tracked model, but only ID, aka a Stub model. – Rasmus Pedersen May 15 '19 at 12:03
  • That's exactly what I did, but it doesnt work - the other post is about collections. From docs.microsoft, their example is to use EntityState.Deleted, not remove, but this has the same effect on SaveChanges, that no delete is sent. – Tig2810 May 17 '19 at 14:52