arame3333
arame3333

Reputation: 10193

Automapper: how to map nested object?

I am struggling with the Automapper syntax. I have a List of PropertySurveys, each containing 1 Property. I wish to map each item on the collection into a new object which combines the 2 classes.

So my code looks like;

            var propertySurveys = new List<PropertyToSurveyOutput >();
            foreach (var item in items)
            {
                Mapper.CreateMap<Property, PropertyToSurveyOutput >();
                var property = Mapper.Map<PropertyToSurvey>(item.Property);
                Mapper.CreateMap<PropertySurvey, PropertyToSurveyOutput >();
                property = Mapper.Map<PropertyToSurvey>(item);
                propertySurveys.Add(property);
            }

My simplified classes look like;

public class Property
{
    public string PropertyName { get; set; }
}

public class PropertySurvey
{
    public string PropertySurveyName { get; set; }
    public Property Property { get; set;}
}

public class PropertyToSurveyOutput
{
    public string PropertyName { get; set; }
    public string PropertySurveyName { get; set; }
}

So in the PropertyToSurveyOutput object, after the first mapping PropertyName is set. Then after the second mapping PropertySurveyName is set, but PropertyName is overridden to null. How do I fix this?

Upvotes: 21

Views: 56762

Answers (3)

heavyd
heavyd

Reputation: 17721

Since v8.1 you can use the IncludeMemebers method in your configuration to map nested objects using existing mappings.

cfg.CreateMap<Property, PropertyToSurveyOutput>();
cfg.CreateMap<PropertySurvey, PropertyToSurveyOutput>()
  .IncludeMembers(src => src.Property);

Upvotes: 5

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236228

First of all, Automapper supports mapping of collections. You don't need to map each item in a loop.

Second - you don't need to re-create map each time you need to map single object. Put mappings creation to application start code (or before first usage of mapping).

And last - with Automapper you can create mapping and define how to do custom map for some properties:

Mapper.CreateMap<PropertySurvey, PropertyToSurveyOutput>()
   .ForMember(pts => pts.PropertyName, opt => opt.MapFrom(ps => ps.Property.PropertyName));

Usage:

var items = new List<PropertySurvey>
{
    new PropertySurvey { 
          PropertySurveyName = "Foo", 
          Property = new Property { PropertyName = "X" } },
    new PropertySurvey { 
          PropertySurveyName = "Bar", 
          Property = new Property { PropertyName = "Y" } }
};

var propertySurveys = Mapper.Map<List<PropertyToSurveyOutput>>(items);

Result:

[
  {
    "PropertyName": "X",
    "PropertySurveyName": "Foo"
  },
  {
    "PropertyName": "Y",
    "PropertySurveyName": "Bar"
  }
]

UPDATE: If your Property class has many properties, you can define two default mappings - one from Property:

Mapper.CreateMap<Property, PropertyToSurveyOutput>();

And one from PropertySurvey. And use first mapping after you used mapping from PropertySurvey:

Mapper.CreateMap<PropertySurvey, PropertyToSurveyOutput>()
      .AfterMap((ps, pst) => Mapper.Map(ps.Property, pst));

Upvotes: 28

Pankaj Gupta
Pankaj Gupta

Reputation: 388

First rule of automapper property name should be same then only it will map correctly and assign the value but in your case one property name is only "Property" and second property name is "PropertyName" so make property name same it will work for you

Upvotes: -5

Related Questions