6

鉴于这两个对象

public class UserModel
{
    public string Name {get;set;}
    public IList<RoleModel> Roles {get;set;}
}

public class UserViewModel 
{
    public string Name {get;set;}
    public IList<RoleViewModel> Roles {get;set;} // notice the ViewModel
}

这是进行映射的最佳方式,还是 AutoMapper 能够Roles自行Roles映射?

应用配置

Mapper.CreateMap<UserModel, UserViewModel>()
    .ForMember(dest => dest.Roles, opt => opt.MapFrom(src => src.Roles));
Mapper.CreateMap<UserViewModel, UserModel>()
    .ForMember(dest => dest.Roles, opt => opt.MapFrom(src => src.Roles));

执行

_userRepository.Create(Mapper.Map<UserModel>(someUserViewModelWithRolesAttached);
4

4 回答 4

15

您不需要映射属性。只需确保属性名称匹配并且它们之间定义了映射。

Mapper.CreateMap<UserModel, UserViewModel>();
Mapper.CreateMap<UserViewModel, UserModel>();
Mapper.CreateMap<RoleModel, RoleViewModel>();
Mapper.CreateMap<RoleViewModel, RoleModel>();

或者用我刚刚发现的更酷的方式:

Mapper.CreateMap<UserModel, UserViewModel>().ReverseMap();
Mapper.CreateMap<RoleModel, RoleViewModel>().ReverseMap();
于 2014-08-27T21:09:59.883 回答
14

这是进行映射的最佳方式,还是 AutoMapper 能够自行将角色映射到角色?

如果属性名称相同,则不必手动提供映射:

Mapper.CreateMap<UserModel, UserViewModel>();
Mapper.CreateMap<UserViewModel, UserModel>();

只要确保内部类型也被映射(RoleViewModelRoleModel

然而,这意味着如果您更改源或目标属性名称,AutoMapper 映射可能会静默失败并导致难以追踪问题(例如,如果您更改UserModel.RolesUserModel.RolesCollection未更改UserViewModels.Roles)。

AutoMapper 提供了一种Mapper.AssertConfigurationIsValid()方法,可以检查所有映射是否有错误并捕获配置错误的映射。有一个与验证您的映射以解决此类问题的构建一起运行的单元测试很有用。

于 2014-08-27T21:09:27.567 回答
0

所有其他答案都好得多(我对每个答案都投了赞成票)。

但我想在这里发布的是一个快速游乐场,您可以在 C# 程序模式下复制并直接粘贴到LinqPad中,并在不影响实际代码的情况下发挥您的想法。

将所有转换移动到 TyperConverter 类的另一件很棒的事情是,您的转换现在是可单元测试的。:)

在这里,您会注意到模型和视图模型几乎相同,除了一个属性。但是通过这个过程,正确的属性被转换为目标对象中的正确属性。

将此代码复制到LinqPad 中,您可以在切换到 C# 程序模式后使用播放按钮运行它。

void Main()
{
    AutoMapper.Mapper.CreateMap<UserModel, UserViewModel>().ConvertUsing(new UserModelToUserViewModelConverter());
    AutoMapper.Mapper.AssertConfigurationIsValid();

    var userModel = new UserModel
    {
        DifferentPropertyName = "Batman",
        Name = "RockStar",
        Roles = new[] {new RoleModel(), new RoleModel() }
    };

    var userViewModel = AutoMapper.Mapper.Map<UserViewModel>(userModel);
    Console.WriteLine(userViewModel.ToString());
}

// Define other methods and classes here
public class UserModel
{
    public string Name {get;set;}
    public IEnumerable<RoleModel> Roles { get; set; }
    public string DifferentPropertyName { get; set; }
}

public class UserViewModel 
{
    public string Name {get;set;}
    public IEnumerable<RoleModel> Roles { get; set; } // notice the ViewModel
    public string Thingy { get; set; }

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine(string.Format("Name: {0}", Name));
        sb.AppendLine(string.Format("Thingy: {0}", Thingy));
        sb.AppendLine(string.Format("Contains #{0} of roles", Roles.Count()));

        return sb.ToString();
    }
}

public class UserModelToUserViewModelConverter : TypeConverter<UserModel, UserViewModel>
{
    protected override UserViewModel ConvertCore(UserModel source)
    {
        if(source == null)
        {
            return null;
        }

        //You can add logic here to deal with nulls, empty strings, empty objects etc
        var userViewModel = new UserViewModel
        {
             Name = source.Name,
             Roles = source.Roles, 
             Thingy = source.DifferentPropertyName
        };
        return userViewModel;
    }
}

public class RoleModel
{
    //no content for ease, plus this has it's own mapper in real life
}

结果来自Console.WriteLine(userViewModel.ToString());

Name: RockStar
Thingy: Batman
Contains #2 of roles
于 2014-08-27T21:31:43.523 回答
0

在 Configure() 方法的 Startup.cs 中:

Mapper.Initialize(config => {
                    config.CreateMap<UserModel, UserViewModel>().ReverseMap();
                    // other maps you want to do.
                });
于 2016-04-04T10:24:20.537 回答