Automapper:如何消除重复映射?

Automapper : how to eleminate repetitive mapping?

我有以下表格结构。这两个表有很多共同的属性超过 20 我只是列出两个。我也有 10 个与此类似的表。这就是表在数据库中的方式。有超过 10 个具有相似属性的具体表,并且没有以任何方式相互连接。我正在使用 POCO 生成器从我的数据库中生成 类。

public class A
 {
    public string name {get;set;}
    public string address {get;set;}
    public string AId {get;set;}
  }

public class B
 {
    public string name {get;set;}
    public string address {get;set;}
    public string BId {get;set;}
  } 

我有以下视图模型:

public class BaseViewModel
 {
    public string Fullname {get;set;}
    public string Fulladdress {get;set;}
   }

public class AviewModel : BaseViewModel
 {
    public string AId {get;set;}
  }

public class BViewModel : BaseViewModel
 {
     public string BId {get;set;}
  } 

当我创建映射时,我必须为我创建的每个 viewModel 重复所有这些。

config.CreateMap<A, AviewModel>()
.ForMember(dest => Fulladdress, opt => opt.MapFrom(src =>.address))
.ForMember(dest => Fullname, opt => opt.MapFrom(src =>.name)).ReverseMap();


config.CreateMap<B, BviewModel>()
.ForMember(dest => Fulladdress, opt => opt.MapFrom(src =>.address))
.ForMember(dest => Fullname, opt => opt.MapFrom(src =>.name)).ReverseMap();

是否可以减少我可能不得不做的重复映射?

您在模型的属性上设置了属性。 这包含它在源对象上映射的 属性 的名称。

然后创建一个接受目标对象和源对象的通用方法,在设置属性的 属性 上找到自定义属性,在目标对象上找到 属性(或反之亦然)然后设置值。

您甚至可以通过询问它是否是 class 属性 来处理嵌套对象。

您需要一个基础 class 作为来源 classes。您在基本源 class 和目标 class 之间创建了一个映射。您将该映射包含在派生的 classes 的映射中。这将允许您重用配置。 The docs。对于简单的情况,您可以使用 As 而不是 Include。

您可以将公共映射代码移至辅助泛型方法。您将 TDestination 类型限制为从 BaseViewModel 派生的 class,从而允许在 ForMember 方法中访问目标成员。对于源映射,您将使用 MapFrom 重载接受 string 属性 name:

public static class CommonMappings
{
    public static IMappingExpression<TSource, TDestination> MapToBaseViewModel<TSource, TDestination>(this IMappingExpression<TSource, TDestination> map)
        where TDestination : BaseViewModel
    {
        return map
            .ForMember(dest => dest.Fulladdress, opt => opt.MapFrom("address"))
            .ForMember(dest => dest.Fullname, opt => opt.MapFrom("name"));
    }
}

那么你可以这样使用它:

config.CreateMap<A, AViewModel>()
    .MapToBaseViewModel()
    // ... specific mappings
    .ReverseMap();

config.CreateMap<B, BViewModel>()
    .MapToBaseViewModel()
    // ... specific mappings
    .ReverseMap();

更新: 原来这个时候最新的AutoMapper 6.1.1的自动反向映射对MapFrom的lambda重载有效,但对string 过载(在 AutoMapper 5 中它根本不起作用)。因此,在它得到修复之前,您可以使用以下 MapFrom(string) 替换:

public static class AMExtensions
{
    public static void From<TSource, TDestination, TMember>(this IMemberConfigurationExpression<TSource, TDestination, TMember> opt, string name)
    {
        var parameter = Expression.Parameter(typeof(TSource), "src");
        var body = Expression.PropertyOrField(parameter, name);
        var selector = Expression.Lambda(body, parameter);
        opt.MapFrom((dynamic)selector);
    }
}

这意味着您需要将原始解决方案中的 MapFrom 调用替换为 From,因为我们不能为扩展方法指定相同的名称,因为它的优先级低于具体方法接口方法。

与基础 class 方法相比,可能需要付出太多努力。但在您无法控制实体设计的情况下很有用 classes.