2

При удалении из репозитория модели (совокупный корень) все ассоциированные агрегаты также должны быть удалены.Паттерн репозитория: удаление корня заполнителя

Я изо всех сил, чтобы реализовать это в моем Entity Framework 6 реализации хранилища шаблона

В моем примере я хочу удалить Customer из CustomerRepository. Все объекты клиента Order также должны быть удалены.

Repository (урезанная):

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 и CustomerRepository (реализация EF):

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

Клиент-код:

customerRepository.Remove(customer); 
unitOfWork.Commit(); 

Исключение брошено:

System.InvalidOperationException: Операция не удалась: отношения не могут быть изменены, так как один или несколько из внешних ключей свойств не является обнуляемым. Когда происходит изменение отношения , соответствующее свойство внешнего ключа устанавливается в нулевое значение. Если внешний ключ не поддерживает нулевые значения, должно быть определено новое отношение , для свойства внешнего ключа должно быть назначено другое значение , или не связанный объект должен быть удален.

Я хотел бы позвонить только item.Orders.Clear(), чтобы указать EF, что ассоциации должны быть удалены.

+0

* «Все объекты Заказчика также должны быть удалены». * Woah there !! Подумайте об этом на секунду ... отменяет ли заказ только потому, что клиент удален? Даже исторические заказы? Следует удалить историю изменений клиента? Мне кажется, что 'Order' также должен быть агрегированным корнем, по крайней мере, в одном контексте. – MattDavey

+0

@MattDavey: К сожалению, я должен был упомянуть, что это пример кода. Плохой пример, как вы указали. – davenewza

+1

Я не верю, что реальный будет лучше. Жесткое удаление - это просто не путь DDD. –

ответ

1

Существует хорошая практика: ничего не удалять:) Вместо этого отметьте его как «удаленный».

Потому что ПОЧЕМУ? Покажите нам настоящие бизнес-требованиям, чтобы физически удалить материал? Не только он замедляет работу (обычно блокировка БД происходит при удалении), вызывает фрагментацию и т. Д., Но в большинстве случаев это абсурдно! Ни один бизнес не позволит вам физически удалить клиента и список заказов!

Бизнес ничего не удаляет. В реальном бизнесе никто не будет искать все документы, относящиеся к конкретному клиенту, и распоряжаться ими в измельчителе. Если они не сделали что-то незаконное и ФБР стучится в дверь :)

Поговорите со своими бизнес-специалистами, которые немного знают о компьютерах (это настоящие бизнес-эксперты). Они расскажут вам, что происходит с клиентами, когда они перестают быть клиентами (возможно, они «заархивированы», возможно, что-то еще или, может быть, просто ничего), а затем моделируют. Это мы, программисты, как правило, изобретаем концепцию «удаления» вещей.

Кроме того, анализ исторической информации может быть действительно полезен некоторое время в будущем!

Есть только два варианта, когда физическое удаление может быть необходимым:

  1. Для экономии дискового пространства (которое не является проблемой больше, когда дисковое пространство так дешево, как грязь)
  2. Чтобы иметь некоторые юридические обязательства физически удалять данные, когда клиент хочет его удалить (что является очень редким требованием и обычно выполняется в определенных доменах).

Для # 1, опять же, в наши дни пространство не является проблемой, поэтому реализация удаления может стоить больше, чем пользы от него. Для # 2 вы все равно хотите быть явным, и вы, вероятно, будете управлять своим хранилищем данных по-разному. Например, вы можете захотеть иметь БД на одного клиента, чтобы вы могли просто отбросить БД и все резервные копии в соответствии с правилом (да, вы должны удалить резервные копии, чтобы официально заявить, что вы не держите удаленные данные больше)

Так какой случай у вас? Почему вы хотите удалить, что вы реально бизнес требований?

2

Ошибка указывает, что ваш четкий метод не удаляет дочерние сущности.
Знаете ли вы о текущем каскаде добавления api при удалении?

HasRequired (t => t.Parent) .WithOptional(). WillCascadeOnDelete (true);

Так что, если вы удаляете объект root, все иждивенцы могут быть удалены с помощью Db. Хотя этот вариант не всегда доступен ...

Поскольку вы используете IRepository ... вы рассматривали, используя некоторый шаблон, как

public int DeleteWhere(Expression<Func<TPoco, bool>> predicate) { 
     var delList = Context.Set<TPoco>().Where(predicate); 
     foreach (var poco in delList) { 
      SetEntityState(poco, EntityState.Deleted); 
     } 
     return delList.Count; 

    } 

var custid = 1; 
var RepOrder - new Respository<Order>(); 
var delcnt = RepOrder.DeleteWhere(t=>t.CustomerId == custid); 

MYContext.SaveChanges() 
Смежные вопросы