Description
Permet le mapping d'un objet de type A vers un objet de type B.
AutoMapper utilise des convention de mapping afin de réduire le paramétrage:
Propriétés de même nom
Flattening
Ignore les références null
Liens
var config = new MapperConfiguration (cfg => {
cfg.CreateMap <Source , Dest >();
cfg.AddProfile <AppProfile >();
cfg.AddProfiles (typeof (ContainerConfig ).Assembly );
});
IMapper mapper = config.CreateMapper ();
IMapper mapper = new Mapper (config);
AProfile.cs
internal sealed class AProfile : Profile
{
public AProfile ()
{
this .CreateAToBMapping ();
this .CreateBToAMapping ();
}
private void CreateAToBMapping ()
{
this .CreateMap <A , B >()
.ForMember (dest => dest .B1 , opt => opt .MapFrom (src => src .A1 ));
}
private void CreateBToAMapping ()
{
this .CreateMap <B , A >()
.ForMember (dest => dest .A1 , opt => opt .MapFrom (src => src .B1 ));
.ForAllOtherMembers (opt => opt .Ignore ());
}
}
Add the nuget package AutoMapper.Extensions.Microsoft.DependencyInjection
Startup.cs
public void ConfigureServices (IServiceCollection services )
{
services.AddAutoMapper (typeof (ProfileTypeFromAssembly1 ), typeof (ProfileTypeFromAssembly2 ));
Exemple
var config = new MapperConfiguration (cfg =>
{
cfg.CreateMap <A , B >()
.ForMember (dst => dst .Q2 , opts => opts .MapFrom (src => src .P2 ));
.ReverseMap ();
});
IMapper mapper = config.CreateMapper ();
C c = new C () { P1 = 3 };
A a = new A () { P1 = 1 , C1 = c };
B b = mapper.Map <B >(a );
class A
{
public int P1 { get ; set ; }
public int P2 { get ; set ; }
public C C1 { get ; set ; }
}
class B
{
public int P1 { get ; set ; }
public int Q2 { get ; set ; }
public int C1P1 { get ; set ; }
}
class C
{
public int P1 { get ; set ; }
}
If the mapping to a destination property has not been configured, you will get an AutoMapper.AutoMapperMappingException
var config = new MapperConfiguration (cfg =>
{
cfg.CreateMap <SpecificItem , SpecificItemDto >()
.ForMember (dest => dest .Code , opt => opt .MapFrom (src => src .Item .Code ));
cfg.CreateMap <SpecificItem , SpecificItemDtoV2 >()
.IncludeMembers (x => x .Item );
cfg.CreateMap <Item , ItemDtoV2 >();
cfg.CreateMap <Item , SpecificItemDtoV2 >(MemberList .None )
.IncludeBase <Item , ItemDtoV2 >();
});
config.AssertConfigurationIsValid ();
IMapper mapper = config.CreateMapper ();
var specificItem = new SpecificItem
{
Item = new Item
{
Id = 1 ,
Code = 2
},
Category = 3
};
var specificItemDto = mapper.Map <SpecificItemDto >(specificItem );
var specificItemDtoV2 = mapper.Map <SpecificItemDtoV2 >(specificItem );
class Item
{
public int Id { get ; set ; }
public int Code { get ; set ; }
}
class SpecificItem
{
public int Category { get ; set ; }
public Item Item { get ; set ; }
}
class SpecificItemDto
{
public int ItemId { get ; set ; }
public int Code { get ; set ; }
public int Category { get ; set ; }
}
class ItemDtoV2
{
public int Id { get ; set ; }
public int Code { get ; set ; }
}
class SpecificItemDtoV2 : ItemDtoV2
{
public int Category { get ; set ; }
}
Unflattening
this .CreateMap <UserDto , User >()
.ForPath (dest => dest .Group .Id , opt => opt .MapFrom (src => src .GroupId ));
List and polymorphism
List <B > listB = Mapper.Map <List <A >, List <B >>(listA );
cfg.CreateMap <Parent1 , Parent2 >()
.Include <Child1 , Child2 >();
cfg.CreateMap <Child1 , Child2 >();
var lp1 = new List <Parent1 > { new Parent1 { P1 = 1 }, new Child1 { P1 = 2 , P2 = 22 } };
var lp2 = mapper.Map <List <Parent2 >>(lp1 );
class Parent1
{
public int P1 { get ; set ; }
}
class Child1 : Parent1
{
public int P2 { get ; set ; }
}
class Parent2
{
public int P1 { get ; set ; }
}
class Child2 : Parent2
{
public int P2 { get ; set ; }
}
var config = new MapperConfiguration (cfg =>
{
cfg.CreateMap <A , B >()
.ForMember (dest => dest .P1 ,
opt => opt .MapFrom ((src , dest , destMember , resContext ) => src.P1 + (int )resContext .Items ["+"]));
});
IMapper mapper = config.CreateMapper ();
var a = new A { P1 = 1 };
var b = mapper.Map <B >(a , opt => opt .Items ["+" ] = 9 );
Map 1 object to multiple objects
class Group
{
public int Id { get ; set ; }
public ICollection <int > UserIds { get ; } = new List <int >();
}
class User
{
public int Id { get ; set ; }
public int GroupId { get ; set ; }
}
Flatten to ValueType
afficher var config = new MapperConfiguration (cfg =>
{
cfg.CreateMap <(Group group, int userId), User >()
.IncludeMembers (s => s .group ) // call the mapping Group → User
.ForMember (dest => dest .Id , opt => opt .MapFrom (src => src .userId ));
cfg.CreateMap <Group , User >()
.ForMember (dest => dest .GroupId , opt => opt .MapFrom (src => src .Id ))
.ForMember (dest => dest .Id , opt => opt .Ignore ());
});
IMapper mapper = config.CreateMapper ();
var group = new Group
{
Id = 9 ,
UserIds = {1 , 2 , 3 }
};
IEnumerable <(int groupId, int userId)> groupAndUserList = group .UserIds.Select (x => ValueTuple .Create (group .Id , x ));
var users = mapper.Map <IEnumerable <User >>(groupAndUserList ).ToList ();
Flatten with a ITypeConverter
afficher var config = new MapperConfiguration (cfg =>
{
cfg.CreateMap <int , User >()
.ForMember (dest => dest .Id , opt => opt .MapFrom (src => src ));
cfg.CreateMap <Group , User >()
.ForMember (dest => dest .GroupId , opt => opt .MapFrom (src => src .Id ))
.ForMember (dest => dest .Id , opt => opt .Ignore ());
cfg.CreateMap <Group , IEnumerable <User >>()
.ConvertUsing <GroupToUsersConverter >();
});
IMapper mapper = config.CreateMapper ();
var group = new Group
{
Id = 9 ,
UserIds = { 1 , 2 , 3 }
};
var users = mapper.Map <IEnumerable <User >>(group ).ToList ();
class GroupToUsersConverter : ITypeConverter <Group , IEnumerable <User >>
{
public IEnumerable <User > Convert (
Group source ,
IEnumerable <User > destination ,
ResolutionContext context )
{
foreach (var userId in source.UserIds)
{
var user = context.Mapper.Map <User >(userId );
context.Mapper.Map (source , user );
yield return user;
}
}
}
cfg.CreateMap <A , B >()
// map A .P2 → B .Q2 if A .P2 > 0
// if A .P2 <= 0 → B .Q2 = 0
.ForMember (dest => dest.Q2 ,
opt =>
{
opt.Condition (src => src .P2 > 0 );
opt.MapFrom (src => src .P2 );
});
cfg.CreateMap <A , B >()
.BeforeMap ((src , dest ) => src.P1 += 1)
.AfterMap ((src , dest ) => dest.P1 -= 1);
Errors
this .CreateMap <Class1 , Class2 >()
.ForMember (dest => dest .Prop1 , opt => opt .MapFrom (src =>
{
// ...
}));
this .CreateMap <Class1 , Class2 >()
.ForMember (dest => dest .Prop1 , opt => opt .MapFrom ((src , dest ) =>
{
// ...
}));
var mapperMock = new Mock <IMapper >();
mapperMock.Setup (x => x .Map <ItemDto >(It .IsAny <Item >()))
.Returns (new ItemDto ());
var configuration = new MapperConfiguration (cfg => cfg.AddProfile <ItemProfile >());
configuration.AssertConfigurationIsValid ();
var mapper = configuration.CreateMapper ();
var item = new Item { };
var itemDto = mapper.Map <ItemDto >(item );
var mappedItem = mapper.Map <Item >(itemDto );
Assert.Equal (item .Property1 , mappedItem .Property1 );
Mock
var mockMapper = new Mock <IMapper >();
this .mockMapper.Setup (m => m .Map <MyEntity , MyDto >(It .IsAny <MyEntity >()))
.Returns (myDto );
var mapper = new Mapper (
new MapperConfiguration (
cfg =>
{
cfg.CreateMap <MyEntity , MyDto >()
.ForMember (dest => dest .Property1 , opt => opt .Ignore ());
}));
Installation
NuGet → AutoMapper
ASP.NET Core
NuGet → AutoMapper.Extensions.Microsoft.DependencyInjection
Startup.cs
public void ConfigureServices (IServiceCollection services )
{
services.AddAutoMapper (typeof (Startup ));
MyController.cs
private readonly IMapper mapper ;
public MyController (IMapper mapper )
{
this .mapper = mapper;
B b = this .mapper.Map <A , B >(a );
Configuration dans Profile