При работе с моделями доменов и классами POCO куда направляются запросы? - PullRequest
7 голосов
/ 06 февраля 2009

Я новичок в моделях доменов, POCO и DDD, поэтому я все еще пытаюсь обдумать несколько идей.

Одна из вещей, которую я пока не могу понять, - это как сделать мои доменные модели простыми и независимыми от хранилища, но при этом способными выполнять некоторые запросы к своим данным богатым способом.

Например, предположим, что у меня есть сущность Order, у которой есть коллекция OrdemItems. Я хочу получить самый дешевый товар по какой-либо причине или список товаров, которых на данный момент нет в наличии. Чего я не хочу, так это получить все элементы заказа из хранилища и отфильтровать их позже (слишком дорого), поэтому я хочу, чтобы в конце концов получился запрос db типа «SELECT .. WHERE ITEM.INSTOCK = FALSE». Я не хочу, чтобы этот SQL-запрос был в моей сущности или какой-либо вариант, если бы он связывал меня с конкретной платформой, такой как запросы NHibernate на Linq2SQL. Какое общее решение в этом случае?

Ответы [ 5 ]

3 голосов
/ 06 февраля 2009

Доменные объекты должны быть независимы от хранилища, вы должны использовать шаблон Repostiory или DAO для сохранения объектов. При таком способе разделения интересов сам объект не должен знать, как он хранится.

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

Вот определение Мартина Фаулера Шаблон хранилища.

3 голосов
/ 11 февраля 2009

Сущности - это «единицы» домена. Репозитории и сервисы ссылаются на них , а не наоборот. Подумайте об этом так: вы носите DMV в своем кармане?

OrderItem не является совокупным корнем; он не должен быть доступен через репозиторий. Его идентичность локальна для Order, означая, что Order всегда будет находиться в области видимости, когда речь идет о OrderItem s.

Сложность поиска дома для запросов заставляет меня задуматься об услугах. В этом случае они представляли бы что-то о и Order, которое трудно знать самому Order.

Объявите намерение в доменном проекте:

public interface ICheapestItemService
{
    OrderItem GetCheapestItem(Order order);
}

public interface IInventoryService
{
    IEnumerable<OrderItem> GetOutOfStockItems(Order order);
}

Объявить реализацию в проекте данных:

public class CheapestItemService : ICheapestItemService
{
    private IQueryable<OrderItem> _orderItems;

    public CheapestItemService(IQueryable<OrderItem> orderItems)
    {
        _orderItems = orderItems;
    }

    public OrderItem GetCheapestItem(Order order)
    {
        var itemsByPrice =
            from item in _orderItems
            where item.Order == order
            orderby item.Price
            select item;

        return itemsByPrice.FirstOrDefault();
    }
}

public class InventoryService : IInventoryService
{
    private IQueryable<OrderItem> _orderItems;

    public InventoryService(IQueryable<OrderItem> orderItems)
    {
        _orderItems = orderItems;
    }

    public IEnumerable<OrderItem> GetOutOfStockItems(Order order)
    {
        return _orderItems.Where(item => item.Order == order && !item.InStock);
    }
}

Этот пример работает с любым поставщиком LINQ. Кроме того, проект данных может использовать NHibernate ISession и ICriteria, чтобы сделать грязную работу.

2 голосов
/ 06 февраля 2009

Поскольку я понимаю этот стиль разработки, вы бы инкапсулировали запрос в метод объекта OrderItemRepository (или, возможно, более подходящего OrderRepository), ответственность которого заключается в том, чтобы общаться с БД с одной стороны и возвращать объекты OrderItem с другой боковая сторона. Репозиторий скрывает детали БД от потребителей экземпляров OrderItem.

0 голосов
/ 11 февраля 2009

Я бы сказал, что не имеет смысла говорить о «Заказе, который содержит только элементы Заказа, которых нет в наличии». «Заказ» (я предполагаю) представляет полный список того, что заказал клиент; если вы фильтруете этот список, вы больше не имеете дело с Орденом как таковым, вы имеете дело с отфильтрованным списком OrderItems.

Я думаю, что возникает вопрос, действительно ли вы хотите рассматривать Заказы как Совокупный корень или хотите ли вы иметь возможность извлекать произвольные списки OrderItems из слоя доступа к данным.

Вы сказали, что фильтрация элементов после их возвращения из базы данных будет слишком дорогой, но если вы не усредняете сотни или тысячи OrderItems для каждого заказа (или есть что-то еще особенно интенсивное в работе с большим количеством OrderItems Возможно, вы пытаетесь оптимизировать преждевременно и усложняете вещи, чем они должны быть. Я думаю, что если вы оставите Order в качестве совокупного корня и фильтра в своей доменной логике, ваша модель станет более чистой для работы.

Если это действительно не случай, и вам нужно отфильтровать базу данных, то вы можете рассмотреть возможность создания отдельного репозитория OrderItem, который бы обеспечивал запросы типа "дай мне все OrderItems для этого заказа которых нет в наличии ". Затем вы должны вернуть их как IList<OrderItem> (или IEnumerable<OrderItem>), поскольку они не полный ордер, а скорее некоторая отфильтрованная коллекция OrderItems.

0 голосов
/ 11 февраля 2009

В слое обслуживания.

...