AutoMapperを使用してオブジェクトを別のオブジェクトにマップする必要があります。トリッキーな質問は、マッピング構成内またはカスタムタイプコンバーター内でマッパーのインスタンス(IMapperのインスタンス)にどのようにアクセスできますか?
以下のコードは機能しませんが、私が達成したい例です-mapper.Map
呼び出しに注意し、マッピングCustomer => CustomerDto
およびCustomer => DetailedCustomerDto
が定義されていると仮定してください。
var config = new MapperConfiguration(
cfg => cfg.CreateMap<Order, OrderDto>()
.ForMember(dst => dst.Customer, src => src.ResolveUsing(o => {
return o.Type == 1
? mapper.Map<Customer, CustomerDto>(o.Customer)
: mapper.Map<Customer, DetailedCustomerDto>(o.Customer)
})
);
クライアント部分は次のとおりです。
var mapper = config.CreateMapper();
var orderDto = mapper.Map<Order, OrderDto>(order);
マッピングするオブジェクトの簡略版は次のとおりです。
public class Order
{
public int Type { get; set; }
public Customer Customer { get; set; }
}
public class Customer
{
public long Id { get; set; }
public string Name { get; set; }
}
public class OrderDto
{
public CustomerDto Customer { get; set; }
}
public class CustomerDto
{
public long Id { get; set; }
}
public class DetailedCustomerDto : CustomerDto
{
public string Name { get; set; }
}
上記のコードからわかるように、Order.Type
の値に基づいて、マッパーはOrder.Customer
プロパティを異なるターゲットにマップする必要があります。 1つのターゲット(DetailedCustomerDto
)が他のターゲット(CustomerDto
)から継承するため、少し注意が必要です。
旧式で非推奨の静的メソッドMapper.Mapの使用はオプションではないことに注意してください。
AutoMapper 5.1.1以降
4つのパラメーターを持つResolveUsing
の別のオーバーロードを使用してマッパーにアクセスできます。4番目のパラメーターはResolutionContext
(context.Mapper
):
var config = new MapperConfiguration(
cfg => {
cfg.CreateMap<Customer, CustomerDto>();
cfg.CreateMap<Customer, DetailedCustomerDto>();
cfg.CreateMap<Order, OrderDto>()
.ForMember(dst => dst.Customer, src => src.ResolveUsing((order, orderDto, i, context) => {
return order.Type == 1
? context.Mapper.Map<Customer, CustomerDto>(order.Customer)
: context.Mapper.Map<Customer, DetailedCustomerDto>(order.Customer);
}));
});
var orderTypeOne = new Order();
orderTypeOne.Type = 1;
orderTypeOne.Customer = new Customer() {
Id = 1
};
var dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeOne);
Debug.Assert(dto.Customer.GetType() == typeof (CustomerDto));
var orderTypeTwo = new Order();
orderTypeTwo.Type = 2;
orderTypeTwo.Customer = new Customer() {
Id = 1
};
dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeTwo);
Debug.Assert(dto.Customer.GetType() == typeof (DetailedCustomerDto));
AutoMapper 5.1.1より前
2つのパラメーターを持つResolveUsing
の別のオーバーロードを使用してマッパーにアクセスできます。最初のパラメーターはResolutionResult
(result.Context.Engine.Mapper
):
var config = new MapperConfiguration(
cfg => {
cfg.CreateMap<Customer, CustomerDto>();
cfg.CreateMap<Customer, DetailedCustomerDto>();
cfg.CreateMap<Order, OrderDto>()
.ForMember(dst => dst.Customer, src => src.ResolveUsing((result, order) => {
return order.Type == 1
? result.Context.Engine.Mapper.Map<Customer, CustomerDto>(order.Customer)
: result.Context.Engine.Mapper.Map<Customer, DetailedCustomerDto>(order.Customer);
}));
});
var orderTypeOne = new Order();
orderTypeOne.Type = 1;
orderTypeOne.Customer = new Customer() {
Id = 1
};
var dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeOne);
Debug.Assert(dto.Customer.GetType() == typeof (CustomerDto));
var orderTypeTwo = new Order();
orderTypeTwo.Type = 2;
orderTypeTwo.Customer = new Customer() {
Id = 1
};
dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeTwo);
Debug.Assert(dto.Customer.GetType() == typeof (DetailedCustomerDto));
Evkの素晴らしい回答に加えて、カスタムコンストラクター(つまり、型に既定のコンストラクターがない)を必要とするconfig/profile内のマッピング内でマッピングを行う必要がある場合、v5.2.0で次のように機能します:
CreateMap<Models.Job, Models.API.Job>(MemberList.Source);
CreateMap<StaticPagedList<Models.Job>, StaticPagedList<Models.API.Job>>()
.ConstructUsing((source, context) => new StaticPagedList<Models.API.Job>(
context.Mapper.Map<List<Models.Job>, List<Models.API.Job>>(source.ToList()),
source.PageNumber,
source.PageSize,
source.TotalItemCount));
この例では、あるオブジェクトタイプのX.PagedListカスタムコレクションタイプを、別のオブジェクトタイプの同等のコレクションにマッピングしています。 lamdba式の最初のパラメーターはソースオブジェクトであり、2番目はResolutionContext
であり、そこからマッパーインスタンスにアクセスしてマップすることができます。