将摘要 属性 映射 class 到目的地
Map class with abstract property to destination
我在将包含抽象 属性 的容器 class 映射到我的视图模型目标 class.
时遇到了一些问题
映射源类
//Container class
public class GiftcardDetailResponse : Response
{
//Instance of either UserGiftcardDTO or ImportedGiftcardDTO
public GiftcardInstanceDTO UserGiftcard { get; set; }
}
public abstract class GiftcardInstanceDTO : BaseDTO
{
public int UserId { get; set; }
public decimal Balance { get; set; }
public string BarcodeValue { get; set; }
public string BarcodeUrl { get; set; }
public string Code { get; set; }
public string Pin { get; set; }
public bool RefreshBalanceSupported { get; set; }
public bool Viewed { get; set; }
public bool IsArchived { get; set; }
public virtual UserDTO User { get; set; }
}
public class UserGiftcardDTO : GiftcardInstanceDTO
{
public int GiftcardId { get; set; }
public DateTimeOffset? ActivatedAt { get; set; }
public DateTimeOffset? BalanceUpdatedAt { get; set; }
public string ClaimUrl { get; set; }
public string ClaimSecret { get; set; }
public PrivacySettings Privacy { get; set; }
public bool IsPending { get; set; }
public bool BoughtAsGift { get; set; }
public virtual GiftcardDTO Giftcard { get; set; }
}
public class ImportedGiftcardDTO : GiftcardInstanceDTO
{
public string RetailerName { get; set; }
public string FrontImage { get; set; }
public string BackImage { get; set; }
}
映射目标类
//Front-end view model
public class GiftcardDetailViewModel
{
public int Id { get; set; }
public string RetailerName { get; set; }
public decimal Amount { get; set; }
public string Image { get; set; }
}
映射配置
CreateMap<GiftcardDetailResponse, GiftcardDetailViewModel>()
.IncludeMembers(src => src.UserGiftcard);
//Automapper should pick a concrete mapping for this
CreateMap<GiftcardInstanceDTO, GiftcardDetailViewModel>()
.IncludeAllDerived();
//Concrete mappings to View Model
CreateMap<UserGiftcardDTO, GiftcardDetailViewModel>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.Image, opt => opt.MapFrom(src => src.Giftcard.Image))
.ForMember(dest => dest.Amount, opt => opt.MapFrom(src => src.Balance))
.ForMember(dest => dest.RetailerName, opt => opt.MapFrom(src => src.Giftcard.Merchant.Name));
CreateMap<ImportedGiftcardDTO, GiftcardDetailViewModel>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.Image, opt => opt.MapFrom(src => src.FrontImage))
.ForMember(dest => dest.Amount, opt => opt.MapFrom(src => src.Balance))
.ForMember(dest => dest.RetailerName, opt => opt.MapFrom(src => src.RetailerName));
问题是,当我将 GiftcardDetailResponse
映射到 GiftcardDetailViewModel
时,Automapper 没有为我的摘要 属性 的派生 class 选择我的显式映射。例如,如果我的代码看起来像这样
var containerClass = new GiftcardDetailResponse();
containerClass.UserGiftcard = new ImportedGiftcardDTO();
var viewModel = MapperWrapper.Mapper.Map<GiftcardDetailViewModel>(containerClass);
执行树看起来像这样
//Automapper generated execution plan
(src, dest, ctxt) =>
{
GiftcardDetailViewModel typeMapDestination;
return (src == null)
? null
: {
typeMapDestination = dest ?? new GiftcardDetailViewModel();
try
{
var resolvedValue = ((src == null) || ((src.UserGiftcard == null) || false)) ? default(int) : src.UserGiftcard.Id;
typeMapDestination.Id = resolvedValue;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(
"Error mapping types.",
ex,
AutoMapper.TypePair,
TypeMap,
PropertyMap);
return default(int);
}
return typeMapDestination;
};
}
它似乎只选择在 GiftcardInstanceDTO
和 GiftcardDetailViewModel
中共享相同名称的属性,而不是使用我定义的映射。
但是我寻找的东西类似于执行树,当我只明确地将我的抽象属性映射到我的视图模型时,例如
var propertyModel = MapperWrapper.Mapper.Map<GiftcardDetailViewModel>(containerClass.UserGiftcard);
这正确地显示了我的派生映射
//Automapper generated execution plan
(src, dest, ctxt) =>
{
GiftcardDetailViewModel typeMapDestination;
return (src == null)
? null
: {
typeMapDestination = dest ?? new GiftcardDetailViewModel();
try
{
var resolvedValue =
{
try
{
return ((src == null) || false) ? default(int) : src.Id;
}
catch (NullReferenceException)
{
return default(int);
}
catch (ArgumentNullException)
{
return default(int);
}
};
typeMapDestination.Id = resolvedValue;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(
"Error mapping types.",
ex,
AutoMapper.TypePair,
TypeMap,
PropertyMap);
return default(int);
}
try
{
var resolvedValue =
{
try
{
return ((src == null) || false) ? null : src.RetailerName;
}
catch (NullReferenceException)
{
return null;
}
catch (ArgumentNullException)
{
return null;
}
};
var propertyValue = (resolvedValue == null) ? null : resolvedValue;
typeMapDestination.RetailerName = propertyValue;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(
"Error mapping types.",
ex,
AutoMapper.TypePair,
TypeMap,
PropertyMap);
return null;
}
try
{
var resolvedValue =
{
try
{
return ((src == null) || false) ? null : src.FrontImage;
}
catch (NullReferenceException)
{
return null;
}
catch (ArgumentNullException)
{
return null;
}
};
var propertyValue = (resolvedValue == null) ? null : resolvedValue;
typeMapDestination.Image = propertyValue;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(
"Error mapping types.",
ex,
AutoMapper.TypePair,
TypeMap,
PropertyMap);
return null;
}
try
{
var resolvedValue =
{
try
{
return ((src == null) || false) ? default(decimal) : src.Balance;
}
catch (NullReferenceException)
{
return default(decimal);
}
catch (ArgumentNullException)
{
return default(decimal);
}
};
typeMapDestination.Amount = resolvedValue;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(
"Error mapping types.",
ex,
AutoMapper.TypePair,
TypeMap,
PropertyMap);
return default(decimal);
}
return typeMapDestination;
};
}
文档说当已经定义了映射时,我可以使用 IncludeMembers
将子对象展平到目标对象。但是当子对象是抽象的时,这种行为在这种情况下似乎无法正常工作。
IncludeMembers
没有实现这种“动态”行为,但您可以这样做:
CreateMap<Source, Destination>().AfterMap((source, destination, context) => context.Mapper.Map(source.InnerSource, destination));
我在将包含抽象 属性 的容器 class 映射到我的视图模型目标 class.
时遇到了一些问题映射源类
//Container class
public class GiftcardDetailResponse : Response
{
//Instance of either UserGiftcardDTO or ImportedGiftcardDTO
public GiftcardInstanceDTO UserGiftcard { get; set; }
}
public abstract class GiftcardInstanceDTO : BaseDTO
{
public int UserId { get; set; }
public decimal Balance { get; set; }
public string BarcodeValue { get; set; }
public string BarcodeUrl { get; set; }
public string Code { get; set; }
public string Pin { get; set; }
public bool RefreshBalanceSupported { get; set; }
public bool Viewed { get; set; }
public bool IsArchived { get; set; }
public virtual UserDTO User { get; set; }
}
public class UserGiftcardDTO : GiftcardInstanceDTO
{
public int GiftcardId { get; set; }
public DateTimeOffset? ActivatedAt { get; set; }
public DateTimeOffset? BalanceUpdatedAt { get; set; }
public string ClaimUrl { get; set; }
public string ClaimSecret { get; set; }
public PrivacySettings Privacy { get; set; }
public bool IsPending { get; set; }
public bool BoughtAsGift { get; set; }
public virtual GiftcardDTO Giftcard { get; set; }
}
public class ImportedGiftcardDTO : GiftcardInstanceDTO
{
public string RetailerName { get; set; }
public string FrontImage { get; set; }
public string BackImage { get; set; }
}
映射目标类
//Front-end view model
public class GiftcardDetailViewModel
{
public int Id { get; set; }
public string RetailerName { get; set; }
public decimal Amount { get; set; }
public string Image { get; set; }
}
映射配置
CreateMap<GiftcardDetailResponse, GiftcardDetailViewModel>()
.IncludeMembers(src => src.UserGiftcard);
//Automapper should pick a concrete mapping for this
CreateMap<GiftcardInstanceDTO, GiftcardDetailViewModel>()
.IncludeAllDerived();
//Concrete mappings to View Model
CreateMap<UserGiftcardDTO, GiftcardDetailViewModel>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.Image, opt => opt.MapFrom(src => src.Giftcard.Image))
.ForMember(dest => dest.Amount, opt => opt.MapFrom(src => src.Balance))
.ForMember(dest => dest.RetailerName, opt => opt.MapFrom(src => src.Giftcard.Merchant.Name));
CreateMap<ImportedGiftcardDTO, GiftcardDetailViewModel>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.Image, opt => opt.MapFrom(src => src.FrontImage))
.ForMember(dest => dest.Amount, opt => opt.MapFrom(src => src.Balance))
.ForMember(dest => dest.RetailerName, opt => opt.MapFrom(src => src.RetailerName));
问题是,当我将 GiftcardDetailResponse
映射到 GiftcardDetailViewModel
时,Automapper 没有为我的摘要 属性 的派生 class 选择我的显式映射。例如,如果我的代码看起来像这样
var containerClass = new GiftcardDetailResponse();
containerClass.UserGiftcard = new ImportedGiftcardDTO();
var viewModel = MapperWrapper.Mapper.Map<GiftcardDetailViewModel>(containerClass);
执行树看起来像这样
//Automapper generated execution plan
(src, dest, ctxt) =>
{
GiftcardDetailViewModel typeMapDestination;
return (src == null)
? null
: {
typeMapDestination = dest ?? new GiftcardDetailViewModel();
try
{
var resolvedValue = ((src == null) || ((src.UserGiftcard == null) || false)) ? default(int) : src.UserGiftcard.Id;
typeMapDestination.Id = resolvedValue;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(
"Error mapping types.",
ex,
AutoMapper.TypePair,
TypeMap,
PropertyMap);
return default(int);
}
return typeMapDestination;
};
}
它似乎只选择在 GiftcardInstanceDTO
和 GiftcardDetailViewModel
中共享相同名称的属性,而不是使用我定义的映射。
但是我寻找的东西类似于执行树,当我只明确地将我的抽象属性映射到我的视图模型时,例如
var propertyModel = MapperWrapper.Mapper.Map<GiftcardDetailViewModel>(containerClass.UserGiftcard);
这正确地显示了我的派生映射
//Automapper generated execution plan
(src, dest, ctxt) =>
{
GiftcardDetailViewModel typeMapDestination;
return (src == null)
? null
: {
typeMapDestination = dest ?? new GiftcardDetailViewModel();
try
{
var resolvedValue =
{
try
{
return ((src == null) || false) ? default(int) : src.Id;
}
catch (NullReferenceException)
{
return default(int);
}
catch (ArgumentNullException)
{
return default(int);
}
};
typeMapDestination.Id = resolvedValue;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(
"Error mapping types.",
ex,
AutoMapper.TypePair,
TypeMap,
PropertyMap);
return default(int);
}
try
{
var resolvedValue =
{
try
{
return ((src == null) || false) ? null : src.RetailerName;
}
catch (NullReferenceException)
{
return null;
}
catch (ArgumentNullException)
{
return null;
}
};
var propertyValue = (resolvedValue == null) ? null : resolvedValue;
typeMapDestination.RetailerName = propertyValue;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(
"Error mapping types.",
ex,
AutoMapper.TypePair,
TypeMap,
PropertyMap);
return null;
}
try
{
var resolvedValue =
{
try
{
return ((src == null) || false) ? null : src.FrontImage;
}
catch (NullReferenceException)
{
return null;
}
catch (ArgumentNullException)
{
return null;
}
};
var propertyValue = (resolvedValue == null) ? null : resolvedValue;
typeMapDestination.Image = propertyValue;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(
"Error mapping types.",
ex,
AutoMapper.TypePair,
TypeMap,
PropertyMap);
return null;
}
try
{
var resolvedValue =
{
try
{
return ((src == null) || false) ? default(decimal) : src.Balance;
}
catch (NullReferenceException)
{
return default(decimal);
}
catch (ArgumentNullException)
{
return default(decimal);
}
};
typeMapDestination.Amount = resolvedValue;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(
"Error mapping types.",
ex,
AutoMapper.TypePair,
TypeMap,
PropertyMap);
return default(decimal);
}
return typeMapDestination;
};
}
文档说当已经定义了映射时,我可以使用 IncludeMembers
将子对象展平到目标对象。但是当子对象是抽象的时,这种行为在这种情况下似乎无法正常工作。
IncludeMembers
没有实现这种“动态”行为,但您可以这样做:
CreateMap<Source, Destination>().AfterMap((source, destination, context) => context.Mapper.Map(source.InnerSource, destination));