EF code first: Как удалить строку из сущности Collection при следующем DDD?

Итак, вот сценарий:

В DDD указано, что вы используете репозиторий для получения совокупного корня, а затем используйте его для добавления/удаления в любые коллекции, которые он имеет.

Добавление простое, вы просто вызываете .Add(Item item) в Collection, который хотите добавить. При сохранении добавляется новая строка в базу данных. Однако удаление отличается - вызов .Remove(Item item) не удаляет элемент из базы данных, он просто удаляет внешний ключ. Итак, пока, да, это технически больше не является частью коллекции, она все еще находится в базе данных.

Чтение, единственное решение - удалить его, используя контекст данных. Но в соответствии с DDD объект домена не должен знать контекст данных, поэтому удаление должно выполняться вне домена.

Каков правильный путь? Или оставляет доступную базу данных с сиротами приемлемой (возможно, запустив процедуру для их очистки)?

Ответ 1

Я решил эту проблему в приложении, в котором я сейчас работаю, используя события домена; концепция DDD Эрик Эванс сказал, что должно было быть в его книге.

В то время как объектам домена не разрешено знать об объектном контексте, IDomainEventHandler - это, поэтому я получил DomainObjectDeletionHandler, который удаляет "удаленные" объекты из контекста объекта, прежде чем элемент управления вернется на мой прикладной уровень и изменения сохраняются.

Для получения дополнительной информации я написал блог о моей реализации событий в домене и о том, как я подошел к подключению всего вместе.

Надеюсь, что помогает:)

Edit

Например, если у вас есть класс Order, который имеет коллекцию OrderItems типа OrderItem:

public class Order
{
    // Other stuff

    public void RemoveOrderItem(int orderItemId)
    {
        var orderItemToRemove = OrderItems.First(oi => oi.Id == orderItemId)

        OrderItems.Remove(orderItemToRemove);

        DomainEvents.Raise(new OrderItemRemoved(orderItemToRemove));
    }
}

Ответ 2

При удалении дочернего объекта из коллекции EF оставит его сиротой, удалив только внешний ключ.

Если вы не хотите явно удалять его с помощью DbContext, вы можете использовать то, что оно называется "Идентификация отношений" (http://msdn.microsoft.com/en-us/library/ee373856.aspx внизу).

Фокус в том, чтобы установить составной первичный ключ для дочернего элемента, включая родительский первичный ключ.

Как только вы это сделаете, при удалении объекта из родительской коллекции он также будет удален из таблицы.

Ответ 3

Я не знаю, является ли это по дизайну, но если подробный объект имеет составной ключ, содержащий его основные столбцы ключа объекта, он будет автоматически удален, если вы удалите его из коллекции основных объектов. Если у вас есть объект Order с ключом OrderID и свойством ICollection OrderLines, дайте OrderLine составной ключ, содержащий OrderID и OrderLineID.

Но так как я не знаю, могу ли я полагаться на это, то я использовал сам вариант, чтобы позволить EF обрабатывать его так, как он есть, и исправить "отсоединенные" (не в терминах EF) подробные объекты на вызовите SaveChanges(), перечислив все измененные объекты и изменив состояние, которое необходимо удалить.

Ответ 4

Почему бы не использовать два репозитория?

var parent = ParentRepo.Get(parentId);
parent.Children.Remove(childId); // remove it from the property Collection
ChildRepo.Delete(childId); // delete it from the database
ParentRepo.Commit(); // calls underlying context.SaveChanges()

Предполагая, что вы используете контексты через IOC/DI, вызов commit с одним репо будет совершать для обоих, иначе просто вызовите ChildRepo.Commit.