Automapper и неизменяемость

Можно ли использовать AutoMapper с неизменяемыми типами?

Например, мой тип домена неизменяем, и я хочу сопоставить с ним свой тип представления.

Я считаю, что это не так, но просто хочу, чтобы это подтвердилось.

Кроме того, лучше всего иметь неизменяемые типы доменов. Как лучше всего сопоставлять типы представлений с типами доменов?


person Noel    schedule 03.02.2010    source источник
comment
Типы доменов неизменяемые? Я не верю, что это было бы правильным утверждением   -  person David    schedule 04.02.2010


Ответы (4)


Обычно я выполняю сопоставление типов представлений с типами предметной области вручную, так как обычно работаю через более сложный интерфейс, используя методы и т.д. Если вы используете AutoMapper для перехода от представления к домену, вы теперь привязаны к анемичной модели домена, независимо от того, решили вы это сделать намеренно или нет.

person Jimmy Bogard    schedule 04.02.2010
comment
Почему вы говорите, что модель домена анемична, если вы используете automapper для сопоставления представления с доменом? Вам понадобится ваша доменная модель, заполненная данными из представления. Это потому, что вы предлагаете вместо этого создавать/заполнять домен с помощью ctors/методов? - person Per Hornshøj-Schierbeck; 14.09.2010
comment
Да, точно. Ознакомьтесь с моей серией статей об укреплении вашего домена: lostechies.com/blogs/jimmy_bogard/archive/2010/02/03/ Если вы посмотрите на другие фреймворки MVC, такие как Rails, концепция модели — это постоянная модель, поэтому вы не не нужен AutoMapper. - person Jimmy Bogard; 17.09.2010
comment
Я думаю, что ваши статьи повлияли на меня, я часто использовал automapper для сопоставления объектов домена с dto/vm, но в конечном итоге мне всегда приходилось искать, как заставить automapper делать что-то другое, просто сопоставляя свойства друг с другом. Выполнение этого вручную не облегчает чтение и отладку. Как вы структурируете код, т. е. куда вы помещаете методы, отображающие свойства объектов? - person sambomartin; 19.10.2012

Предположим, что вам действительно нужно неизменяемое свойство для вашего типа домена, скажем, Id. Тип вашего домена может выглядеть примерно так:

public class DomainType
{
    public DomainType(int id)
    {
        Id = id;
    }

    public int Id { get; }
    // other mutable properties
    // ...
}

Затем вы можете использовать ConstructUsing с помощью общедоступного конструктора по вашему выбору, например:

CreateMap<ViewType, DomainType>()
    .ConstructUsing(vt => new DomainType(vt.Id));

Затем сопоставьте все изменяемые свойства обычным способом.

person user1007074    schedule 22.07.2018
comment
Если ViewType также содержит свойство с именем Id, вам не нужно беспокоиться о .ConstructUsing(). AutoMapper будет использовать конструктор и автоматически сопоставлять имена параметров с именами исходных свойств. - person 9Rune5; 20.01.2020
comment
Вот ответ, с которым я могу согласиться. Спасибо. - person Michael Puckett II; 21.06.2020

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

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

Для меня не имеет большого смысла то, что ваша модель предметной области неизменна. Как вы его обновляете? Все приложение доступно только для чтения? И если да, то зачем вообще нужно сопоставлять с модель домена, а не из? Неизменяемая модель предметной области звучит... довольно бесполезно.

P.S. Я предполагаю, что вы имеете в виду этот AutoMapper, а не функция автоматического сопоставления в Fluent NHibernate или даже какая-то другая совершенно другая вещь. Если это не так, вы должны быть более конкретными и добавить теги для своей платформы/языка.

person Aaronaught    schedule 04.02.2010
comment
для меня не имеет большого смысла то, что ваша модель предметной области неизменна. Это так. представьте, что вы используете, например, CQRS. модель чтения должна быть неизменной. Другой пример — объект-значение. - person Fabio Marreco; 01.08.2018
comment
Я как бы не согласен с этим комментарием и приношу свои извинения, но неизменяемые DTO действительны, и использование стандартного картографа также допустимо. Вы хотите, чтобы ваша логика сопоставления была универсальной, поэтому, независимо от того, отображаете ли вы byte[], неизменяемые типы, строки или что-то еще, я рекомендую сделать ее стандартной. Использование AutoMapper может быть излишним для сопоставления всех типов, но использование одного и того же интерфейса сопоставления — нет. Я считаю, что AutoMapper должен искать и пытаться использовать сопоставление конструктора, если поля являются частными, однако вы даже можете установить поле только для чтения с отражением, поэтому мое чутье подсказывает мне, что это возможно. - person Michael Puckett II; 21.06.2020

У нас есть неизменяемые объекты, использующие шаблон построителя. Для их сопоставления требуется немного больше стандартного кода, но это возможно.

// ViewModel
public class CarModel : IVehicleModel 
{
    private CarModel (Builder builder)
    {
        LicensePlate = builder.LicensePlate;
    }    

    public string LicensePlate { get; }

    //
    public Builder
    {
        public string LicensePlate { get; set; }
    }
}


// Model
public class CarViewModel : IVehicleViewModel
{
    private CarViewModel (Builder builder)
    {
        LicensePlate = builder.LicensePlate ;
    }    

    public ILicensePlate LicensePlate { get; }

    //
    public Builder
    {
        public ILicensePlate LicensePlate { get; set; }
    }
}

У нашего AutoMapper Profiles есть три зарегистрированных сопоставления:

        CreateMap<IVehicleModel, CarViewModel.Builder>();
        CreateMap<CarViewModel.Builder, IVehicleViewModel>().ConvertUsing(x => x.Build());
        CreateMap<IVehicleModel, IVehicleViewModel>().ConvertUsing<VehicleModelTypeConverter>();

Затем VehicleModelTypeConverter определяет двухэтапное преобразование:

    public IVehicleViewModel Convert(IVehicleModel source, IVehicleViewModel destination,
        ResolutionContext context)
    {
        var builder = context.Mapper.Map<CarViewModel.Builder>(source);
        var model = context.Mapper.Map<IVehicleViewModel>(builder);

        return model;
    }

(Реализация ITypeListConverter<string, ILicensePlate> выполняет это сопоставление).

Использование в нашей системе как обычно:

var result = _mapper<IVehicleViewModel>(_carModel);

Это использует AutoMapper v7.0.1

person Paddy    schedule 21.02.2020
comment
@LucianBargaoanu в этой статье рассматривается создание объекта с использованием параметров общедоступного конструктора, что, как я думал, не сработает для меня. - person Paddy; 24.02.2020
comment
Это не должно быть публичным. - person Lucian Bargaoanu; 24.02.2020