c# - AutoMapper:领域模型和 View 模型之间的双向深度映射

标签 c# asp.net-mvc viewmodel automapper automapper-3

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

我的模型是:

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) 将 Automapper 用于深层属性的更好方法?

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
}

-布伦丹

附言重构领域模型不是解决方案。

P.P.S 可以通过扩展方法和一些时髦的反射来设置深层属性来清理上面的代码......但如果可能的话我宁愿使用自动映射器功能。

最佳答案

这也可以通过这种方式完成:

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

但与您的解决方案没有太大区别。

此外,您还可以通过创建从您的模型到您的内部类的映射来做到这一点:

Mapper.CreateMap<ClientNotificationOptionsViewModel, ContactDetails>();

Mapper.CreateMap<ClientNotificationOptionsViewModel, NotificationSettings>();

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

您不需要在新映射中指定 ForMember,因为属性在两个类中具有相同的名称。

关于c# - AutoMapper:领域模型和 View 模型之间的双向深度映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22851860/

相关文章:

c# - Node.JS 非阻塞 IO 和其他框架,如 ASP.NET MVC 通过 async/await 非阻塞 io

android - Jetpack Compose - 更改 viewModel 中的变量会导致 viewModel 状态发生更改吗?

c# - MVC3 绑定(bind)自定义集合

c# - Kinect V2 - 如何将 kinect v2 坐标转换为现实生活中的测量值?

c# - 将日期作为字符串传递 - 防止 json.net 解析日期

c# - 如何在不破坏现有客户端的情况下使用 C# 重新实现旧的 DCOM 服务器?

c# - webview 中的 HTML 格式数据绑定(bind)到 listview

c# - 授权属性意外工作

c# - 将自定义 View 对象从 Controller 传递到 View

c# - 在此示例 MVVM 应用程序中使用模型是否有意义?