AutoMapper:域模型和视图模型之间的双向深度映射

布伦丹·希尔

我需要在平面ViewModel和深度结构化Domain模型之间映射两种方式。这将是我们解决方案中的常见情况。

我的模型是:

public class Client 
{
   ...
   public NotificationSettings NotificationSettings { get; set; }
   public ContactDetails ContactDetails { get; set; }
   ...
}

public class NotificationSettings
{
    ...
    public bool ReceiveActivityEmails { get; set; }
    public bool ReceiveActivitySms { get; set; }
    ...
}

public class ContactDetails
{
    ...
    public string Email { get; set }
    public string MobileNumber { get; set; }
    ...
}

public class ClientNotificationOptionsViewModel
{
    public string Email { get; set }
    public string MobileNumber { get; set; }
    public bool ReceiveActivityEmails { get; set; }
    public bool ReceiveActivitySms { get; set; }
}

映射代码:

Mapper.CreateMap<Client, ClientNotificationOptionsViewModel>()
    .ForMember(x => x.ReceiveActivityEmails, opt => opt.MapFrom(x => x.NotificationSettings.ReceiveActivityEmails))
    .ForMember(x => x.ReceiveActivitySms, opt => opt.MapFrom(x => x.NotificationSettings.ReceiveActivitySms))
    .ForMember(x => x.Email, opt => opt.MapFrom(x => x.ContactDetails.Email))
    .ForMember(x => x.MobileNumber, opt => opt.MapFrom(x => x.ContactDetails.MobileNumber));

// Have to use AfterMap because ForMember(x => x.NotificationSettings.ReceiveActivityEmail) generates "expression must resolve to top-level member" error
Mapper.CreateMap<ClientNotificationOptionsViewModel, Client>()
    .IgnoreUnmapped()
    .AfterMap((from, to) =>
    {
        to.NotificationSettings.ReceiveActivityEmail = from.ReceiveActivityEmail;
        to.NotificationSettings.ReceiveActivitySms = from.ReceiveActivitySms;
        to.ContactDetails.Email = from.Email;
        to.ContactDetails.MobileNumber = from.MobileNumber;
    });


...

// Hack as ForAllMembers() returns void instead of fluent API syntax
public static IMappingExpression<TSource, TDest> IgnoreUnmapped<TSource, TDest>(this IMappingExpression<TSource, TDest> expression)
{
    expression.ForAllMembers(opt => opt.Ignore());
    return expression;
}

我不喜欢它是因为:

1)麻烦

2)第二个映射几乎取消了Automapper的功能并手动实现了工作-唯一的优势是在整个代码中引用Automapper的一致性

谁能建议:

a)将自动映射器用于深层属性的更好方法?

b)像这样执行双向映射的更好方法?

c)关于在这种情况下是否应该使用Automapper的建议?是否有令人信服的理由不选择手动编码的更简单方法?例如。:

void MapManually(Client client, ClientNotificationOptionsViewModel viewModel)
{
    viewModel.Email = client.ContactDetails.Email;
    // etc
}  

void MapManually(ClientNotificationOptionsViewModel viewModel, Client client)
{
    client.ContactDetails.Email = viewModel.Email;
    // etc
}

-布伦丹

PS重组域模型不是解决方案。

PPS可以通过扩展方法和一些时髦的反射来清理上面的代码来设置深层属性...但是我宁愿使用automapper功能。

布伦丹·希尔

最后,我发现AutoMapper不适合我的情况。

相反,我构建了一个自定义实用程序来提供双向映射和深度属性映射,允许进行如下配置。考虑到我们项目的范围,我相信这是合理的。

BiMapper.CreateProfile<Client, ClientNotificationsViewModel>()
    .Map(x => x.NotificationSettings.ReceiveActivityEmail, x => x.ReceiveActivityEmail)
    .Map(x => x.NotificationSettings.ReceiveActivitySms, x => x.ReceiveActivitySms)
    .Map(x => x.ContactDetails.Email, x => x.Email)
    .Map(x => x.ContactDetails.MobileNumber, x => x.MobileNumber);

BiMapper.PerformMap(client, viewModel);
BiMapper.PerformMap(viewModel, client);

抱歉,我无法分享实施,因为它是一项商业工作。但是,我希望它可以帮助其他人知道并非不可能自己构建,并且可以提供优于AutoMapper或手动完成的优势。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

域模型和实体模型是否相同

Swagger OpenAPI模型和JPA实体之间的映射

模型,视图和控制器之间的Ruby on Rails关系

不同数据库和域模型之间的Hibernate映射

如何也使用Automapper映射导航属性视图模型

如何使用自动映射器在模型和视图模型之间映射父子关系船

域模型和EF Core模型

在微服务中创建域模型和视图模型的正确方法

如何使用AutoMapper将3个对象映射到视图模型

AutoMapper 5.1-映射模型和扩展模型

使用参数AutoMapper映射视图模型子级

使用Automapper映射复杂的继承模型

如何使用AutoMapper从MVC控制器从域模型映射到视图模型

将视图和表映射到EF中的相同模型?

视图模型和请求-响应消息传递模式之间的MVC映射

春季模型与模型和视图之间的区别

使用自动映射器将加入的域模型映射到视图模型

在模型和DTO之间映射对象的问题

在Rails show视图中映射和链接模型实例

JavaScript客户端和WebAPI之间的模型映射

通过notifychanged或command属性在父视图模型和子视图模型之间进行通信?

使用Factory进行映射和重构的域模型快照

在域模型和视图模型之间共享逻辑的正确方法

重构视图模型和视图之间的xaml映射

DDD NoSQL 存储和域模型与视图模型

从域模型创建视图模型:MVVM

使用 htaccess 将模型和视图重写为子域

Automapper 双向复杂映射

在模型之间实现双向导航属性