簡體   English   中英

如何在 AutoMapper 的 MapperConfiguration 中使用 mapper.Map?

[英]How to use mapper.Map inside MapperConfiguration of AutoMapper?

我需要使用 AutoMapper 將一個對象映射到另一個對象。 棘手的問題是如何訪問映射配置內部或自定義類型轉換器內部的映射器實例(IMapper 實例)?

下面的代碼不起作用,但是它是我想要實現的示例 - 請注意mapper.Map調用並假設映射Customer => CustomerDtoCustomer => 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映射到不同的目標。 由於一個目標 ( DetailedCustomerDto ) 從另一個目標 ( CustomerDto ) 繼承而來,因此變得有點棘手。

請注意,過時和不推薦使用的靜態方法 Mapper.Map 的使用不是一種選擇

自 AutoMapper 8.0 及更高版本以下 5.1.1 的答案仍然適用,但請注意ResolveUsing的使用已替換為MapFrom的重載,但簽名在其他方面保持一致。

從 AutoMapper 5.1.1 開始

您可以使用帶有四個參數的ResolveUsing另一個重載ResolveUsing映射器,其中第四個是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 之前的版本

您可以使用帶有兩個參數的ResolveUsing另一個重載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 對我有幫助的出色答案之外,如果您需要在需要自定義構造函數(即該類型沒有默認構造函數)的配置/配置文件中的映射中進行映射,以下內容將在 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 表達式的第一個參數是您的源對象,第二個參數是您的ResolutionContext ,您可以從中訪問要映射的映射器實例。

我正在使用Automapper 9 ,上面的答案對我不起作用。 然后為了解決我和你一樣的問題,我使用.afterMap ,就像這樣:

public class AutoMapperOrder : Profile
{
        public AutoMapperOrder()
        {
            CreateMap<Customer, CustomerDto>()
            //...

            CreateMap<Customer, DetailedCustomerDto>()
            //...

            CreateMap<Order, OrderDto>()
                .AfterMap((src, dest, context) => {
                dest.Customer = src.Type == 1
                    ? context.Mapper.Map<Customer, CustomerDto>(src.Customer)
                    : context.Mapper.Map<Customer, DetailedCustomerDto>(src.Customer)
            }
        }
    }
}

我希望能幫助某人。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM