2017-09-14 62 views
1

我有以下表结构。这两张桌子有很多共同的属性超过20我刚刚列出两个。还有我有10个表与此类似。这就是表格在数据库中的方式。有超过10个具有类似属性的混凝土表格,并且不以任何方式相互连接。我使用POCO生成器从我的数据库生成类。Automapper:如何选择重复映射?

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;} 
    } 

我有以下的ViewModels:

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;} 
    } 

当我创建映射我不得不重复这一切,我已经创建的每个视图模型。

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(); 

是否有可能减少我可能需要做的重复映射?

+1

为什么不提取和使用基类为您的实体,类似于你正在做你的视图模型。 –

+0

@IvanStoev所以我使用POCO生成的类我不想手动更改类中的任何东西。所以这意味着每次有人更新.tt文件,我的结构已经消失了。 – hamadkh

+0

其实你是对的似乎是最好的解决方案 – hamadkh

回答

2

您可以将通用映射代码移至辅助通用方法。您将限制TDestination类型为从BaseViewModel派生的类,从而允许以ForMember方法访问目标成员。而对于源映射你将使用MapFrom超负荷接受string属性名称:

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); 
    } 
} 

这意味着你需要在原来的解决方案与From取代MapFrom电话,因为我们不能给的扩展方法相同的名称因为它比具体界面方法的优先级低。

与基准类方法相比,可能会花费太多精力。但有用的情况下,你无法控制实体类的设计。

+1

这也行得通,所以我在POCO生成的类之外创建了一个基类,并将其配置为忽略常用字段并从我的基类继承。我确实做得很好。我仍然会将这个commonMapping类用于其他小型重复映射。非常感谢 !! – hamadkh

+1

虽然很聪明,但这更像是一种破解:)我只会在没有办法创建源代码基类/接口时才使用它。 –

+0

是的,我也只是测试它多一点,似乎reverseMap()不起作用呢?它获取数据但不会发布给我? – hamadkh

0

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

然后,您制作一个接受目标对象和源对象的通用方法,该方法在设置属性的属性和目标对象上的属性(反之亦然)上找到customattribute,然后设置该值。

你甚至可以通过询问是否它的一个类属性来处理嵌套对象。

+0

因此,不是重复的流畅配置,而是建议重复数据注释(自定义属性)。有什么不同 - 你仍然需要做很多重复的工作。 –

+0

呃不可以?你只需要为一个类的属性定义属性一次。到源类型或反之亦然。比通用类为您处理映射更少关注发送给映射器的类。不涉及重复性任务。 –

2

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