When deleting a model (aggregate root) from the repository, all associated aggregates must be deleted too.
I am struggling to implement this in my Entity Framework 6 implementation of the repository pattern
In my example, I want to delete a Customer
from the CustomerRepository
. All the customer's Order
objects should also be deleted.
Repository (stripped down):
public interface IRepository<T> where T : DomainEntity
{
void Remove(T item);
}
public class EntityFrameworkRepository<T> : IRepository<T> where T : DomainEntity
{
private readonly DbSet<T> dbSet;
public DbContext context;
public EntityFrameworkRepository(IUnitOfWork unitOfWork)
{
context = entityFrameworkUnitOfWork.context;
dbSet = dbSet = context.Set<T>();
}
public virtual void Remove(T item)
{
DbEntityEntry dbEntityEntry = context.Entry(item);
if (dbEntityEntry.State == EntityState.Detached)
{
dbSet.Attach(item);
}
dbSet.Remove(item);
}
}
public class EntityFrameworkUnitOfWork : IUnitOfWork
{
public readonly DbContext context;
public EntityFrameworkUnitOfWork()
{
this.context = new ReleaseContext();
}
public void Commit()
{
context.SaveChanges();
}
}
ICustomerRepository
and CustomerRepository
(EF implementation):
public interface ICustomerRepository : IRepository<Customer>
{
IEnumerable<Customer> GetAllActive();
}
public class CustomerRepository : EntityFrameworkRepository<Customer>, ICustomerRepository
{
public CustomerRepository(IUnitOfWork unitOfWork)
: base(unitOfWork)
{ }
public override void Remove(Order item)
{
item.Orders.Clear();
base.Remove(item);
}
}
Client-code:
customerRepository.Remove(customer);
unitOfWork.Commit();
Exception thrown:
System.InvalidOperationException: 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.
I would except calling item.Orders.Clear()
to indicate to EF that the associations must be deleted.
There is a good practice: don't delete anything :) Mark it as "deleted" instead.
Because WHY? Show us a real business requirement to physically delete stuff? Not only it slows things down (usually DBs lock a lot while deleting), causes fragmentation, etc., but in most of the cases it is absurd! No business would allow you do physically delete a customer and a list of orders!
Business does not delete anything. In the real business no one will go an find all the papers related to a particular customer and dispose of them in a shredder. Unless they did something illegal and FBI is knocking at the door :)
Talk to your business experts who know a little about computers (these are the real business experts). They will tell you what happens to customers when they stop being customers (perhaps they are "archived", perhaps something else, or perhaps just nothing) and then model it. It is us, programmers, usually invent the concept of "deleting" stuff.
Besides, analysing historical information can be really helpful some time in the future!
There are only two options when physical delete can be necessary:
For #1, again, space is not a problem these days so implementing delete can cost more than benefit from it. For #2 you want to be explicit anyway and you would probably manage your data storage differently. For example you may want to have a DB per client then so you can just drop the DB and all the backups to comply to the regulation (yes, you must remove backups in order to legally say that you don't hold the deleted data anymore)
So which case is yours? Why you want to delete, what are you real business requirements?