EntityState.Deleted does not work, Remove(entity)

2019-02-17 16:32发布

问题:

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

回答1:

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).



回答2:

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.