Какое правильное место для запроса прогнозов DTO? - PullRequest
0 голосов
/ 08 мая 2019

По разным причинам (разделение задач, производительность) я хочу прекратить отправку доменных сущностей в мои представления и вместо этого использовать проекции DTO.

Я хочу использовать запросы ORM для создания своих DTO, выбирая толькополя, которые мне нужны от одного или нескольких объектов.

Какое место для этого нужно сделать?

  • Хранилища: нет, они не должны возвращатьсяDTO
  • Контроллеры: я бы хотел сохранить их как можно более тонкими и избегать их выполнения запросов и / или отображения

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

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

яЕсть ли образец для этого?

Ответы [ 3 ]

0 голосов
/ 10 мая 2019

Dto является объектом прикладного уровня.То, что вы хотите, это заполнить его непосредственно из БД.Это сторона запросов cqrs, где у вас нет модели с расширенным доменом, такой как командная сторона, у вас есть только проекции (dtos), подходящие для клиента.Это модель запроса (чтения).

ОБНОВЛЕНИЕ:

Это объекты шаблона, который я использую, аналогично команде, но у запроса есть результат:

public interface QueryResult {}

Простой DTO (или их список) с выходными данными для клиентов.

public interface Query<QR extends QueryResult> {}

Простой DTO с входными данными (критериями поиска) для выполнения запроса.

public interface QueryHandler <QR extends QueryResult, Q extends Query<QR>> {
    public QR handle ( Q query );
}

Объект, который выполняет запрос.

ПРИМЕР:

  • Приложение, управляющее данными о сотрудниках, отделах и т. Д.компании.
  • Вариант использования: Дайте мне список сотрудников (только имя, адрес электронной почты, должность, зарплата) сотрудников моложе 30 лет с зарплатой более 2000 евро.

Код:

class EmployeeDto {
    private String name;
    private String email;
    private String departmentName;
    private double salary;
    ...
    <<getters and setters>>
    ...
}

class EmployeeDtoList implements QueryResult {
    private List<EmployeeDto> employeeDtos;
    ...
    <<getter and setter>>
    ...
}

class EmployeesByAgeAndSalary implements Query<EmployeeDtoList> {
    private Calendar maxAge;
    private double minSalary;
    ...
    <<getters and setters>>
    ...
}

class EmployeesByAgeAndSalaryHandler implements QueryHandler<EmployeeDtoList,EmployeesByAgeAndSalary> {
    ...
    @Override
    public EmployeeDtoList handle(EmployeesByAgeAndSalary query) {
        ...
        <<retrieve from the database the data we need to return,
        applying the criteria for the age and salary given in the "query" arg>>
        ...
    }
}

- Фасад, который использует клиент, является посредником (интерфейс с этим методом):

public <QR extends QueryResult,Q extends Query<QR>> QR executeQuery(Q query);

Посредник будет реализован классом, которыйуправляет реестром обработчика запросов, поэтому он перенаправляет запрос в обработчик запросов, связанный с данным запросом.

Это похоже на шаблон команды, но с запросами.

0 голосов
/ 14 мая 2019

Отличный вопрос,

Вы помещаете их в прикладной слой. Шаблон, который вы ищете, называется Query Service.

Посмотрите, как Вон Вернон (автор Реализации доменного управления) сделал в своем репозитории на github:

https://github.com/VaughnVernon/IDDD_Samples/tree/master/iddd_collaboration/src/main/java/com/saasovation/collaboration/application/forum/data

Затем он заполняет их непосредственно из БД в службе запросов (CQRS):

public ForumDiscussionsData forumDiscussionsDataOfId(String aTenantId, String aForumId) {
    return this.queryObject(
            ForumDiscussionsData.class,
            "select "
            +  "forum.closed, forum.creator_email_address, forum.creator_identity, "
            +  "forum.creator_name, forum.description, forum.exclusive_owner, forum.forum_id, "
            +  "forum.moderator_email_address, forum.moderator_identity, forum.moderator_name, "
            +  "forum.subject, forum.tenant_id, "
            +  "disc.author_email_address as o_discussions_author_email_address, "
            +  "disc.author_identity as o_discussions_author_identity, "
            +  "disc.author_name as o_discussions_author_name, "
            +  "disc.closed as o_discussions_closed, "
            +  "disc.discussion_id as o_discussions_discussion_id, "
            +  "disc.exclusive_owner as o_discussions_exclusive_owner, "
            +  "disc.forum_id as o_discussions_forum_id, "
            +  "disc.subject as o_discussions_subject, "
            +  "disc.tenant_id as o_discussions_tenant_id "
            + "from tbl_vw_forum as forum left outer join tbl_vw_discussion as disc "
            + " on forum.forum_id = disc.forum_id "
            + "where (forum.tenant_id = ? and forum.forum_id = ?)",
            new JoinOn("forum_id", "o_discussions_forum_id"),
            aTenantId,
            aForumId);
}
0 голосов
/ 09 мая 2019

Ваши DTO представляют модель чтения .Для этого я обычно использую query"layer" (хотя я склонен думать больше с точки зрения проблем, а не слоев).Обычно я использую I{Aggregate}Query так же, как и у меня I{Aggregate}Repository.

. Интерфейс возвращает данные в максимально простом формате:

namespace Company.Project.DataAccess
{
    public interface ICustomerQuery
    {
        int CountMatching(Query.Customer.Specification specification);
        int Count();
        IEnumerable<DataRow> RowsMatching(Query.Customer.Specification specification); // perhaps OK for simple cases
        IEnumerable<Query.Customer> Matching(Query.Customer.Specification specification); // for something more complex
    }
}   

Я также создаюQuery пространство имен, которое содержит мои DTO.Это означает, что домен, например, будет содержать Customer AR, а пространство имен Query также будет содержать Customer, но, поскольку оно находится в пространстве имен Query, нет никакой двусмысленности, и мне не нужнодобавить суффикс DTO:

namespace Company.Project.DataAccess.Query
{
    public class Customer
    {
        public class Specification
        {
            public string Name { get; private set; }

            public Specification WithName(string name)
            {
                Name = name;

                return this;
            }
        }

        public string Name { get; set; }
        public string Address { get; set; }
    }
}
...