Automapper and immutability
Asked Answered
S

5

11

Is it possible to use AutoMapper with Immutable types?

For example my Domain type is immutable and I want to map my view type to this.

I believe it is not but just want this confirmed.

Also as it is best practice to have your domain types immutable, what is the best practice when mapping your view types to domain types?

Slacker answered 3/2, 2010 at 21:44 Comment(1)
Domain types immutable? I don't beleive that would be a correct statementTestaceous
V
8

I typically do the mapping from view types to domain types by hand, as I'll typically be working through a more complex interface, using methods and so on. If you use AutoMapper to go from view to domain, you're now locked in to an anemic domain model, whether you've intentionally decided to or not.

Vivl answered 4/2, 2010 at 4:5 Comment(3)
Why would you say the domain model is anemic, if you use automapper to map from view to domain? You will need your domain model populated with the data from the view somehow. Is it because you propose creating/populating the domain through ctors/methods instead?Consternation
Yep, exactly. Check out my series on strengthening your domain: lostechies.com/blogs/jimmy_bogard/archive/2010/02/03/… If you look at other MVC frameworks, like Rails, the concept of a Model is a persistent model, so you don't need AutoMapper.Vivl
I think your articles swayed me, i've often used automapper to map domain objects to dto/vm but always end up having to look up how to make automapper do the something other that simply map the properties to one another. Doing it by hand not makes it easier to read and debug. How do you structure the code - i.e. where do you put the methods that map the objects' properties?Mesh
H
3

Suppose that you really did want an immutable property on your Domain type, say Id. Your domain type might look something like this:

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

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

Then you can use ConstructUsing using a public constructor of your choice, such as:

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

Then map all the mutable properties in the normal way

Homopolar answered 22/7, 2018 at 14:34 Comment(2)
If ViewType also contains a property named "Id", then you need not bother with .ConstructUsing(). AutoMapper will use the constructor and match parameter names with source property names automatically.Fleischman
Here's an answer I can get on board with. Thank you.Billups
R
1

AutoMapper relies on property setters to do its work, so if you have read-only properties, AutoMapper won't be of much use.

You could override the mapping behaviour and, for example, configure it to invoke a specific constructor, but that basically defeats the purpose of AutoMapper because then you are doing the mapping manually, and you've only succeeded in adding a clumsy extra step in the process.

It doesn't make a lot of sense to me that your domain model is immutable. How do you update it? Is the entire application read-only? And if so, why would you ever need to map to your domain model as opposed to from? An immutable domain model sounds... pretty useless.

P.S. I'm assuming that you mean this AutoMapper and not the auto-mapping feature in Fluent NHibernate or even some other totally different thing. If that's wrong then you should be more specific and add tags for your platform/language.

Rame answered 4/2, 2010 at 4:27 Comment(2)
"it doesn't make a lot of sense to me that your domain model is immutable.": It does. imagine you are using CQRS for example. the read model should be immutable. Another example is a valueobject.Footlights
I sort of disagree with this comment and apologize but immutable DTOs are valid and using a standard mapper is just as valid. You want your mapping logic to be universal so whether mapping byte[], immutable types, strings, or what have you, then I recommend making it standard. Using AutoMapper may be over kill for all types mapping but using the same mapping interface isn't. I believe AutoMapper should look for and try to use constructor mapping if fields are private, however, you can even set a readonly field with reflection so my gut tells me it's possible.Billups
L
1

We have immutable objects using the builder pattern. Mapping them takes a little more boilerplate code, but it is possible

// 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; }
    }
}

Our AutoMapper Profiles have three mappings registered:

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

The VehicleModelTypeConverter then defines a two stage conversion:

    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;
    }

(An implementation of ITypeListConverter<string, ILicensePlate> carries out that mapping).

Usage in our system is as normal:

var result = _mapper<IVehicleViewModel>(_carModel);

This is using AutoMapper v7.0.1

Lough answered 21/2, 2020 at 11:28 Comment(2)
@LucianBargaoanu that article covers constructing an object using parameters on a public constructor, which I didn't think would work for meLough
It doesn't have to be public.Adolpho
F
1

You can use Automapper with classes or records that have properties init only setters. This is new in C# 9.0.

Automapper can set the properties at object creation because the properties have init only setters, but after Automapper has mapped them, they are locked in (immutable).

https://www.tsunamisolutions.com/blog/c-90-records-and-dtos-a-match-made-in-redmond

Fulgurite answered 15/9, 2021 at 17:7 Comment(2)
You've posted this link to three different posts now, with barely any additional information. While answers may reference external resources, they should also be self-contained, such that readers aren't dependent on them. Additionally, if this happens to be your blog, you should be sure to review Stack Overflow's self-promotion rules.Danish
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Eddra

© 2022 - 2024 — McMap. All rights reserved.