When you call the DbSet.Remove(entity)
in EF 6.X, you are really using the ObjectContext.DeleteObject(entity). This is the code that is called in the InternalSet<TEntity>
class:
public virtual void Remove(object entity)
{
DebugCheck.NotNull(entity);
if (!(entity is TEntity))
{
throw Error.DbSet_BadTypeForAddAttachRemove("Remove", entity.GetType().Name, typeof(TEntity).Name);
}
InternalContext.DetectChanges();
InternalContext.ObjectContext.DeleteObject(entity);
}
If the foreign key on the dependent entity is not nullable, by default, when you configure your relationship, Code First sets cascade delete on the relationship,so, when you call the Remove
method, it also deletes all the child objects in the constrained relationship (EF will generate the delete statements for the parent entity and the related entities). If a foreign key on the dependent entity is nullable, Code First does not set cascade delete on the relationship, and when the principal is deleted the foreign key will be set to null
.
Now, when you use the second variant changing the state of a parent entity as Deleted
(bEntityEntry.State = EntityState.Deleted
), EF attaches a whole entity graph to the context with specified state to parent entity and with the children three things can happen depending on the type of relationship you have:
If the relationship is optional, i.e. the foreign key that refers from the child to the parent in the database allows NULL
values, this foreign will be set to null and if you call SaveChanges
this NULL
value for the childEntity
will be written to the database (i.e. the relationship between the two is removed). This happens with a SQL UPDATE
statement. No DELETE
statement occurs.
If the relationship is required (the FK doesn't allow NULL
values) and the relationship is not identifying (which means that the foreign key is not part of the child's (composite) primary key) you have to either add the child to another parent or you have to explicitly delete the child (with DeleteObject
then). If you don't do any of these a referential constraint is violated and EF will throw an exception when you call SaveChanges
- the infamous "The relationship could not be changed because one or more of the foreign-key properties is non-nullable" exception or similar.
If the relationship is identifying (it's necessarily required then because any part of the primary key cannot be NULL
) EF will mark the childEntity
as Deleted
as well. If you call SaveChanges
a SQL DELETE
statement will be sent to the database. If no other referential constraints in the database are violated the entity will be deleted, otherwise an exception is thrown.
Fo more info, you can check this post and this too.
So, IMHO it's better create a generic Delete
method this way:
public virtual void Delete(T entity)
{
//Attach the entity to your context
DbSet.Attach(entity);
// Remove the current entity and the related entities in case of your relationship was configured with cascade delete
DbSet.Remove(entity);
}
Update
Me neither see the point of the author in use both variants.Usually when you create a Remove
generic method is used one of this two variants, not both at the same time. If you use the DbSet.Remove
I don't see the point in check the state, this method will do the job for you. If you use the second variant, I would create a method like this:
public virtual void Delete(T entity)
{
// An Added entity does not yet exist in the database. If it is then marked as deleted there is
// nothing to delete because it was not yet inserted, so just make sure it doesn't get inserted.
dbEntityEntry.State == EntityState.Added
? EntityState.Detached
: EntityState.Deleted);
}