Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EntityState.Deleted does not work, Remove(entity) does?

I've been struggling with EF when trying to read records, then delete those records in the same transaction. I was initially using the EntityState.Deleted method, which would give an error:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

But if I change it to like I have below, using .Remove(), then all is well.

  1. What is the difference and best times to use .Remove() vs .Deleted?
  2. How could I make this work using the .Deleted method? I have tried creating a new instance of the context to my repository to read and another to delete, but then got errors related to IEntityTracker can't track multiple instances... I also tried .Include on the initial read to load the dependent records into EF so it knows about and deletes them. I also tried .Detaching the read records first. All to no avail.

Here is the method in question. Note that I do have a generic repository which uses the .Deleted method which has served me well until this scenario (reading then deleting the same records.)

//Delete Allocation Need and AllocatedContainers for alloc need id
public ActionConfirmation<int> DeleteAllocRecords(int intFacilityId, AllocNeedSourceTypes needSourceType, int intNeedSourceId)
{
var context = new InventoryMgmtContext();
var repository = new AllocationNeedRepository(context);

//Delete Allocation Need and hence children in Allocated Containers
var srcType = needSourceType.ToString();
List<AllocationNeed> allocNeeds = repository.SearchFor(
    x => x.FacilityId == intFacilityId
    && x.NeedSourceType == srcType
    && x.NeedSourceId == intNeedSourceId
).ToList();

//var deleteRepository = new Repository<AllocationNeed>(); <--tried separate instance of context to delete...no worky.

foreach (AllocationNeed allocNeed in allocNeeds)
{
    try
    {
        //NO WORK: context.Entry(allocNeed).State = System.Data.EntityState.Deleted;
        context.AllocationNeeds.Attach(allocNeed); 
        context.AllocationNeeds.Remove(allocNeed); <-- Works
        context.SaveChanges();
    }
    catch (Exception ex)
    {
        return ActionConfirmation<int>.CreateFailureConfirmation(ex.Message, allocNeed.Id);
    }
}
like image 804
crichavin Avatar asked Apr 24 '13 14:04

crichavin


People also ask

How to Delete an entity in entity framework?

Deleting an entity is done using the Remove or RemoveRange method of the DbSet. Alternatively, you can also set the entity state as Deleted . We can delete records either in connected or disconnected Scenarios. We will also look at how to remove multiple records from the database using the RemoveRange method.

Which method is used to let the DbContext know an entity should be deleted?

Remove(Object) Begins tracking the given entity in the Deleted state such that it will be removed from the database when SaveChanges() is called.

What does EntityState Modified do?

State = EntityState. Modified; , you are not only attaching the entity to the DbContext , you are also marking the whole entity as dirty. This means that when you do context. SaveChanges() , EF will generate an update statement that will update all the fields of the entity.


2 Answers

Remove will also remove the child objects, but using Deleted will not. You should really be using Remove for this very reason. If you really want to use Deleted, you'd have to make your foreign keys nullable, but then you'd end up with orphaned records (which is one of the main reasons you shouldn't be doing that in the first place).

like image 124
mattytommo Avatar answered Sep 27 '22 23:09

mattytommo


1.) What is the difference and best times to use .Remove() vs .Deleted?

It appears that setting the entity's state to Deleted causes SaveChanges() to delete only that specific entity from the database, not taking into account other rows that may reference it via a non-null foreign-key column.

Remove() will take into account rows that are part of the relationship.

2.) How could I make this work using the .Deleted method?

If you have ON CASCADE DELETE behavior specified for the related rows, the database should handle it automatically. This is the default behavior when you let EF generate the database.

like image 28
w.brian Avatar answered Sep 27 '22 23:09

w.brian