« Automapper » : différence entre les versions
Apparence
Aucun résumé des modifications |
|||
Ligne 103 : | Ligne 103 : | ||
{{info | If the mapping to a destination property has not been configured, you will get an {{boxx|AutoMapper.AutoMapperMappingException}}}} | {{info | If the mapping to a destination property has not been configured, you will get an {{boxx|AutoMapper.AutoMapperMappingException}}}} | ||
= Unflattening = | |||
<kode lang='cs'> | <kode lang='cs'> | ||
// unflattening UserDto.GroupId → User.Group.Id | // unflattening UserDto.GroupId → User.Group.Id | ||
Ligne 110 : | Ligne 110 : | ||
</kode> | </kode> | ||
= List and polymorphism = | |||
<kode lang='cs'> | <kode lang='cs'> | ||
// avec une liste | // avec une liste | ||
Ligne 150 : | Ligne 150 : | ||
* [http://docs.automapper.org/en/stable/Mapping-inheritance.html Mapping Inheritance] | * [http://docs.automapper.org/en/stable/Mapping-inheritance.html Mapping Inheritance] | ||
= [http://codebuckets.com/2016/09/24/passing-parameters-with-automapper/ Pass parameter to the mapping] = | |||
<kode lang='cs'> | <kode lang='cs'> | ||
var config = new MapperConfiguration(cfg => | var config = new MapperConfiguration(cfg => | ||
Ligne 165 : | Ligne 165 : | ||
</kode> | </kode> | ||
= Map 1 object to multiple objects = | |||
<kode lang='cs'> | <kode lang='cs'> | ||
// map 1 Group to many User | // map 1 Group to many User | ||
Ligne 182 : | Ligne 182 : | ||
</kode> | </kode> | ||
== Flatten to ValueType == | |||
<kode lang='cs' collapsed> | <kode lang='cs' collapsed> | ||
var config = new MapperConfiguration(cfg => | var config = new MapperConfiguration(cfg => | ||
Ligne 207 : | Ligne 207 : | ||
</kode> | </kode> | ||
== Flatten with a ITypeConverter == | |||
<kode lang='cs' collapsed> | <kode lang='cs' collapsed> | ||
var config = new MapperConfiguration(cfg => | var config = new MapperConfiguration(cfg => | ||
Ligne 248 : | Ligne 248 : | ||
} | } | ||
} | } | ||
</kode> | |||
= [https://docs.automapper.org/en/stable/Conditional-mapping.html#preconditions Conditional Mapping] = | |||
<kode lang='cs'> | |||
cfg.CreateMap<A, B>() | |||
// map A.P2 → B.Q2 if A.P2 != 0 | |||
.ForMember(dest => dest.Q2, | |||
opt => | |||
{ | |||
opt.Condition(src => src.P2 != 0); | |||
opt.MapFrom(src => src.P2); | |||
}); | |||
</kode> | </kode> | ||
Version du 10 novembre 2020 à 20:43
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
- Getting Started
- Static and Instance API
- AutoMapper.Collection bibliothèque externe pour géré les collections
- Map 1 object to list of objects
Setup and configuration
var config = new MapperConfiguration(cfg => {
// configure mapping from Source to Dest
cfg.CreateMap<Source, Dest>();
// load the configuration from AppProfile
cfg.AddProfile<AppProfile>();
// load the configuration from all classes who inherits from Profile in the current assembly
cfg.AddProfiles(typeof(ContainerConfig).Assembly);
});
IMapper mapper = config.CreateMapper();
IMapper mapper = new Mapper(config);
|
Profile
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()); // ignore all other members
}
}
|
Dependency Injection
![]() |
Add the nuget package AutoMapper.Extensions.Microsoft.DependencyInjection |
Startup.cs |
public void ConfigureServices(IServiceCollection services)
{
// add as parameter one type for each assembly
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)); // map A.P2 → B.Q2
.ReverseMap(); // map B → A
});
IMapper mapper = config.CreateMapper();
C c = new C() { P1 = 3 };
A a = new A() { P1 = 1, C1 = c };
B b = mapper.Map<B>(a);
// b.P1 = 1, b.Q2 = 2, b.C1P1 = 3
class A
{
public int P1 { get; set; }
public int P2 { get; set; }
public C C1 { get; set; }
}
class B
{
public int P1 { get; set; } // mapping par convention avec A.P1
public int Q2 { get; set; } // mapping par configuration avec A.P2
public int C1P1 { get; set; } // mapping par flattening avec A.C1.P1
}
class C
{
public int P1 { get; set; }
}
|
![]() |
If the mapping to a destination property has not been configured, you will get an AutoMapper.AutoMapperMappingException |
Unflattening
// unflattening UserDto.GroupId → User.Group.Id
this.CreateMap<UserDto, User>()
.ForPath(dest => dest.Group.Id, opt => opt.MapFrom(src => src.GroupId));
|
List and polymorphism
// avec une liste
List<B> listB = Mapper.Map<List<A>, List<B>>(listA);
// polymorphism
cfg.CreateMap<Parent1, Parent2>()
.Include<Child1, Child2>();
// IncludeAllDerived(); to include all the derived classes
// without the include, the resulting list contains only Parent2 objects (no Child2 objects)
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);
// Parent2, Child2
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; }
}
|
Pass parameter to the mapping
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
// map 1 Group to many User
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
|
Flatten with a ITypeConverter
|
Conditional Mapping
cfg.CreateMap<A, B>()
// map A.P2 → B.Q2 if A.P2 != 0
.ForMember(dest => dest.Q2,
opt =>
{
opt.Condition(src => src.P2 != 0);
opt.MapFrom(src => src.P2);
});
|
Errors
A lambda expression with a statement body cannot be converted to an expression tree
this.CreateMap<Class1, Class2>()
.ForMember(dest => dest.Prop1, opt => opt.MapFrom(src =>
{
// ...
}));
// use a new overload of MapFrom
this.CreateMap<Class1, Class2>()
.ForMember(dest => dest.Prop1, opt => opt.MapFrom((src, dest) =>
{
// ...
}));
|
MOQ
var mapperMock = new Mock<IMapper>();
mapperMock.Setup(x => x.Map<ItemDto>(It.IsAny<Item>()))
.Returns(new ItemDto());
|
Unit tests
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);
|
Installation
NuGet → AutoMapper
ASP.NET Core
NuGet → AutoMapper.Extensions.Microsoft.DependencyInjection
Startup.cs |
public void ConfigureServices(IServiceCollection services)
{
services.AddAutoMapper();
|
MyController.cs |
private readonly IMapper _mapper;
public MyController(IMapper mapper)
{
_mapper = mapper;
B b = _mapper.Map<A, B>(a);
|
Configuration dans Profile