С помощью AutoMapper можно точно сопоставить данные полной точности с деноминационными данными и из них. - PullRequest
0 голосов
/ 21 февраля 2019

Сценарий

Я использую Google Protocol Buffers в сервис-ориентированном приложении.Чтобы уменьшить объем данных, отправляемых клиентам, у меня есть «деноминации» данного DTO.Например:

message CustomerDto {
    string id = 1;

    // A denomination to be used in the context of listing customers.
    message ListDataDto {
        string name = 1;
    }

    // A denomination to be used when full customer data is required.
    message FullDataDto {
        string name = 1;
        string address = 2;
        string phone = 3;
        // etc.
    }

    oneof data {
        ListDataDto list = 2;
        FullDataDto full = 3;
    }
}

Когда клиенты извлекают данные для отображения в списке, я могу отправить им CustomerDto объекты с полем data, установленным в ListDataDto.Когда им требуются полные данные клиента, я устанавливаю data на FullDataDto.Он работает нормально.

За API-интерфейсом клиенты шунтируются с помощью полнофункционального прото, как это:

message Customer {
    string id = 1;
    string name = 2;
    string address = 3;
    string phone = 4;
}

Что сейчас вызывает у меня боль, так это отображение между этими типами с помощью AutoMapper.

Отображение из полноценных данных в деноминационные данные

Отображение из Customer в CustomerDto требует дополнительной контекстной информации, чтобы знать, какой тип data является целевым.

В настоящее время я делаю это:

config
    .CreateMap<Customer, CustomerDto>()
    .ForMember(
        x => x.List,
        options =>
        {
            options
                .Condition((_, __, ___, ____, context) => context.Items[nameof(CustomerDto.DataOneofCase)] is Dto.DataOneofCase.List);
            options
                .MapFrom(x => x);
        })
    .ForMember(
        x => x.Full,
        options =>
        {
            options
                .Condition((_, __, ___, ____, context) => context.Items[nameof(CustomerDto.DataOneofCase)] is CustomerDto.DataOneofCase.Full);
            options
                .MapFrom(x => x);
        });

Вызовы Condition довольно неприятные, отчасти благодаря тому факту, что C # не позволяет использовать _ в качестве сброса в этомконтекст.Я полагаю, что я мог бы, если бы до него дошло, создать метод расширения с именем ConditionalOnDataDenomination или что-то такое, что скрывает уродливый вызов Condition.

Однако мне интересно, не хватает ли мне чистящего средства?подход в целом.

Отображение из деноминационных данных в данные с полной достоверностью

Отображение из CustomerDto в Customer еще сложнее.В настоящее время я делаю это:

config
    .CreateMap<CustomerDto.Types.FullDataDto, Customer>()
    .ForMember(
        x => x.Id,
        options => options.Ignore());
config
    .CreateMap<CustomerDto, Customer>()
    .ConvertUsing(
        (source, destination, context) =>
        {
            if (source.DataCase != CustomerDto.DataOneofCase.Full)
            {
                throw new NotSupportedException("Can only convert from full-fidelity data.");
            }

            var mapper = context.Mapper;
            var customer = mapper.Map<Customer>(source.Full);
            customer.Id = source.Id;

            return customer;
        });

Этот подход состоит из двух отображений:

  1. От объекта FullDataDto с полной точностью до Customer.
  2. От CustomerDto до Customer.

Первое отображение раздражает, потому что я должен игнорировать каждое поле, определенное в CustomerDto, которое находится за пределами FullDataDto.В этом случае у меня есть только 1 (Id), но на самом деле у меня есть несколько основных частей данных, которые будут всегда отправляться (например, Id, Revision, Status).Таким образом, первое отображение становится многословным.Я пытался вызывать различные Ignore методы, но ни один из них не казался подходящим.

Второе сопоставление кажется немного ... уродливым.Это правильно гарантирует, что мы сопоставляем только данные с полной точностью (для клиента не имеет смысла отправлять, например, CustomerDto с ListDataDto внутри него обратно на сервер).Затем он опирается на сопоставление, созданное на шаге 1, для сопоставления большей части данных.Наконец, он вручную копирует поля, которые обязательно были проигнорированы в первом отображении.Опять же, у меня есть несколько таких полей.

Вопрос

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...