Как правильно использовать DTO в этом случае?

У меня следующий доменный класс:

public class Product
{
    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<Product> RelatedProducts { get; set; }
}

У меня есть следующий класс DTO:

public class ProductDTO
{
    public ProductDTO(Product product)
    {
        Id = product.Id;
        Name = product.Name;
    }

    public Guid Id { get; private set; }
    public string Name { get; private set; }
}

У меня на службе есть следующий метод:

public ProductDTO GetBySlug(string slug)
{
    Product product = productRepository.GetBySlug(slug);
    return (product != null) ? new ProductDTO(product) : null;
}

В моем контроллере есть следующее действие:

public ActionResult Details(string slug)
{
    ProductDTO viewModel = productService.GetBySlug(slug);
    return View("Details", viewModel);
}

Прочитав немного, я понял, что использование DTO в качестве модели представления нормально, поскольку текущий сценарий прост и понятен. Мое замешательство возникает, когда данные, которые я хочу вернуть, становятся немного сложнее. Предположим, я также хочу вернуть в представление список связанных продуктов. Куда бы мне добавить этот список?

Я читал, что DTO - это плоская версия объекта вашего домена, которая используется для передачи данных. Означает ли это, что общий список, содержащий связанные продукты, не должен быть разрешен внутри DTO? Ответ, который я получил до сих пор, говорит об этом. Как мне затем передать сопутствующие товары контроллеру?

Один из вариантов:

Вместо того, чтобы возвращать ProductDTO в сервисе, я бы создал новый класс, содержащий ProductDTO и список типа ProductDTO для связанных продуктов, и вернул бы его из сервиса. Затем в контроллере я бы либо передал новый класс в представление, либо создал отдельный ProductViewModel, содержащий ProductDTO и список типа ProductDTO для связанных продуктов, заполнил его и передал в представление.

Это хорошая или плохая идея? Почему?

Спасибо


person Thomas    schedule 08.08.2010    source источник


Ответы (1)


Я бы вообще не стал помещать этот список в DTO, потому что он, естественно, там не принадлежит. И я также не уверен, что вы имеете в виду под «классом-оболочкой». Все, что вам нужно, это список продуктов, и совершенно нормально иметь в службе другой метод, который возвращает этот список.

Следовательно, в вашем сервисе будет что-то вроде этого:

public IList<ProductDTO> GetRelatedProducts(ProductDTO productDTO)
{
    ...

Самая важная идея, лежащая в основе модели представления (то, что выше называется службой), заключается в том, что она является посредником между пользовательским интерфейсом и бизнес-моделью. Другими словами: он организует и объединяет бизнес-модель в соответствии с пользовательским интерфейсом. И если пользовательскому интерфейсу в какой-то момент нужен список связанных продуктов, тогда служба должна его доставить. Это действительно так просто, и здесь совершенно неважно, есть ли эта концепция в самой бизнес-модели.

HTH! Томас

P.S. Если ваши DTO становятся больше, а ваши списки длиннее, вы можете подумать о введении другого (упрощенного) DTO только с именем и каким-либо идентификатором, чтобы уменьшить количество ненужных данных, которые вы должны получить из репозитория.

person Thomas Weller    schedule 08.08.2010
comment
Томас, спасибо за ответ. Я отредактировал вопросы и добавил, что связанные продукты уже получены из репозитория в приведенном выше коде. Сущность продукта модели предметной области имеет список с уже загруженными связанными продуктами. Я просто не понимаю, как я могу отображать сопутствующие товары. Полезно знать, что список не принадлежит DTO, что немного упрощает работу. - person Thomas; 08.08.2010
comment
Томас, я немного отредактировал вопрос, чтобы немного прояснить ситуацию. Если у вас есть второй, вы можете еще раз взглянуть? - person Thomas; 09.08.2010
comment
Если ваша бизнес-модель - продукт уже имеет метод GetRelatedProducts (), ваш ProductDTO также может иметь его (возвращает список ProductDTO, доступный только для чтения). Если вам нужно доставить связанные продукты в свой пользовательский интерфейс, не создавая ProductDTO, может быть проще иметь дополнительный метод обслуживания ... Оба варианта одинаково возможны и «действительны», на самом деле все зависит от того, что имеет больше смысла в вашем пользовательском интерфейсе контекст / рабочий процесс. - person Thomas Weller; 09.08.2010
comment
Да, в настоящее время товар и сопутствующие товары заполняются одновременно с помощью одной транзакции базы данных. Значит, в этом случае допустимо и имеет смысл добавить список ProductDTO, доступный только для чтения, в мой ProductDTO? - person Thomas; 09.08.2010
comment
Похоже, в данном случае это было бы самым легким и простым делом. Так что тебе стоит пойти на это ... - person Thomas Weller; 09.08.2010