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.
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);
}
}
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.
Remove(Object) Begins tracking the given entity in the Deleted state such that it will be removed from the database when SaveChanges() is called.
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.
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With