Во-первых, вы должны разоблачить интерфейсы, чтобы получить ссылки на ваш сводный корень (т. Е. Порядок()). Используйте шаблон Factory для создания нового экземпляра корня агрегата (т. Е. Порядка()).
С учетом сказанного, методы, используемые в вашем сводном корне, позволяют получить доступ к связанным с ним объектам - а не к самому себе. Кроме того, никогда не выставляйте сложные типы как общедоступные по совокупным корням (т. Е. Коллекция Lines() IList, указанная в примере). Это нарушает закон decremeter (sp ck), который говорит, что вы не можете «Dot Walk» перейти к методам, таким как Order.Lines.Add().
А также вы нарушаете правило, которое позволяет клиенту получить доступ к ссылке на внутренний объект на сводном корне. Совокупные корни могут возвращать ссылку внутреннего объекта. Пока внешнему клиенту не разрешается ссылаться на этот объект. I.e., ваш «OrderLine», который вы передаете в RemoveLine(). Вы не можете разрешить внешнему клиенту контролировать внутреннее состояние вашей модели (то есть Order() и его OrderLines()). Поэтому вы должны ожидать, что OrderLine будет новым экземпляром, чтобы действовать соответствующим образом.
public interface IOrderRepository
{
Order GetOrderByWhatever();
}
internal interface IOrderLineRepository
{
OrderLines GetOrderLines();
void RemoveOrderLine(OrderLine line);
}
public class Order
{
private IOrderRepository orderRepository;
private IOrderLineRepository orderLineRepository;
internal Order()
{
// constructors should be not be exposed in your model.
// Use the Factory method to construct your complex Aggregate
// Roots. And/or use a container factory, like Castle Windsor
orderRepository =
ComponentFactory.GetInstanceOf<IOrderRepository>();
orderLineRepository =
ComponentFactory.GetInstanceOf<IOrderLineRepository>();
}
// you are allowed to expose this Lines property within your domain.
internal IList<OrderLines> Lines { get; set; }
public RemoveOrderLine(OrderLine line)
{
if (this.Lines.Exists(line))
{
orderLineRepository.RemoveOrderLine(line);
}
}
}
Не забыли свой завод для создания новых экземпляров ордена():
public class OrderFactory
{
public Order CreateComponent(Type type)
{
// Create your new Order.Lines() here, if need be.
// Then, create an instance of your Order() type.
}
}
Ваш внешний клиент не имеет право на доступ к IOrderLinesRepository непосредственно через интерфейс, чтобы получить ссылку объекта ценности в вашем сводном корне. Но я стараюсь блокировать это, заставляя мои ссылки использовать методы Aggregate Root. Таким образом, вы можете пометить IOrderLineRepository выше как внутреннюю, чтобы он не был открыт.
Я на самом деле группирую все свои Совокупные корневые творения на несколько Заводов. Мне не понравился подход «Некоторые совокупные корни будут иметь фабрики для сложных типов, другие - нет». Гораздо проще иметь одну и ту же логику в рамках моделирования домена. «О, так что Sales() - это совокупный корень, такой как Order(). Для него тоже должна быть фабрика».
Наконец, если у вас есть комбинация, то есть SalesOrder(), которая использует две модели Sales() и Order(), вы должны использовать Сервис для создания и действия в этом экземпляре SalesOrder(), поскольку ни Sales() или Order() Aggregate Roots, а также их репозитории или фабрики, собственный контроль над объектом SalesOrder().
Я очень рекомендую this free book от Abel Avram и Floyd Marinescu по дизайну Domain Drive Design (DDD), так как он напрямую отвечает на ваши вопросы, в печати на 100 страниц большой печати. Наряду с тем, как больше разделить ваши объекты домена на модули и т. Д.
Edit: добавлено больше кода
Я предполагаю, что это расширение означает, что вы не используете ORM непосредственно на своих объектах домена. Я надеялся, что смогу избежать дополнительной работы, описанной выше, при условии, что linq to sql автоматически сохранит изменения, внесенные в объект домена ... –
y, это настоящая проблема. Я делаю это. Я вижу комментарии все время на Nhibernate, поддерживая более сложные сценарии, но я не смотрел, как он играет с этим типом сценария (который не просто использует POCOs) – eglasius
Спасибо; хотя и не ужасно идеальный (ошибка LTS, а не ваш ответ), похоже, это подтверждает мои собственные догадки о том, как мне нужно это делать ... – Funka