AutoMapper with complex types

I'm having a problem trying to use complex types with AutoMapper.

I have two objects, a domain and a ViewModel that utlize in my View;

ViewModel

public class RegisterCoupleModel
{
    [Required(ErrorMessage = "campo obrigatório")]
    [Display(Name = "Primeiro nome", Order = 0, GroupName = "Noivo")]
    [StringLength(60)]
    public string FistNameGroom
    {
        get;
        set;
    }

    [Required(ErrorMessage = "campo obrigatório")]
    [Display(Name = "Último nome", Order = 1, GroupName = "Noivo")]
    [StringLength(60)]
    public string LastNameGroom
    {
        get;
        set;
    }

    [Required(ErrorMessage = "campo obrigatório")]
    [RegularExpression(@"^[w-.]+@([w-]+.)+[w-]{2,4}$", ErrorMessage = "Formato de email inválido.")]
    [DataType(DataType.EmailAddress)]
    [Remote("IsEmailAvailable", "Validation", "", ErrorMessage = "este email já está sendo usado por outro usuário.")]
    [Display(Name = "Email", Order = 2, GroupName = "Noivo")]
    [StringLength(180)]
    public string EmailGroom
    {
        get;
        set;
    }

    [Required(ErrorMessage = "campo obrigatório")]
    [Display(Name = "Primeiro nome", Order = 0, GroupName = "Noiva")]
    [StringLength(60)]
    public string FistNameBride
    {
        get;
        set;
    }

    [Required(ErrorMessage = "campo obrigatório")]
    [Display(Name = "Último nome", Order = 1, GroupName = "Noiva")]
    [StringLength(60)]
    public string LastNameBride
    {
        get;
        set;
    }

    [Required(ErrorMessage = "campo obrigatório")]
    [RegularExpression(@"^[w-.]+@([w-]+.)+[w-]{2,4}$", ErrorMessage = "Formato de email inválido.")]
    [DataType(DataType.EmailAddress)]
    [Remote("IsEmailAvailable", "Validation", "", ErrorMessage = "este email já está sendo usado por outro usuário.")]
    [Display(Name = "Email", Order = 2, GroupName = "Noiva")]
    [StringLength(180)]
    public string EmailBride
    {
        get;
        set;
    }

    [Required(ErrorMessage = "campo obrigatório")]
    [Display(Name = "Url")]
    [RegularExpression(@"^[a-zA-Z0-9_-.+]{5,22}$", ErrorMessage = "Chave inválida")]
    [StringLength(22, MinimumLength = 5, ErrorMessage = "A chave deve ter entre {0} e {1} caracteres.")]
    [Remote("IsKeywordAvaliable", "Validation")]
    public string UrlKeyword
    {
        get;
        set;
    }

    [Display(Name = "Voce é humano?")]
    [UIHint("ReCaptcha")]
    public string ReCaptcha
    {
        get;
        set;
    }
}

Domain Object

public class Couple
{
    [Key]
    public Guid Id { get; set; }
    public string UrlKeyword { get; set; }
    public virtual Partner Groom { get; set; }
    public virtual Partner Bride { get; set; }
    public DateTime Marriage { get; set; }
    public DateTime Dating { get; set; }
    public DateTime Engagement { get; set; }
    public virtual ICollection<User> Users { get; set; }
}

If you look you will see that my object Couple domain has the properties has Bride and Groom which are actually the same type .

How can I map my domain object Couple with the RegisterCoupleModel ?

Here I made it as far as:

In settings automapper tried to do something like:

CreateMap<RegisterCoupleModel, Couple>()
    .ForMember(dest => dest.Bride.User.FirstName, opt => opt.MapFrom(source => source.FistNameBride))
    .ForMember(dest => dest.Bride.User.LastName, opt => opt.MapFrom(source => source.LastNameBride))
    .ForMember(dest => dest.Bride.User.Email, opt => opt.MapFrom(source => source.EmailBride))
    .ForMember(dest => dest.Groom.User.FirstName, opt => opt.MapFrom(source => source.FistNameGroom))
    .ForMember(dest => dest.Groom.User.LastName, opt => opt.MapFrom(source => source.LastNameGroom))
    .ForMember(dest => dest.Groom.User.Email, opt => opt.MapFrom(source => source.EmailGroom));

But the error below is displayed:

Expression 'dest => dest.Bride.User.FirstName' must resolve to top-level member. Parameter name: lambdaExpression

I know this takes the act of trying to use to map properties with nested types.

But how can I map RegisterCoupleModel to Couple and the two properties Bride and Groom are the same type?

I found a question here on StackOverflow that looks like this, but it helped me.


What i would do is encapsulate the properties for FirstNameBride , LastNameBride , EmailBride , FirstNameGroom , LastNameGroom , EmailGroom into a nested viewmodel type, let's say PersonDetails :

public class PersonDetails
{
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public string Email { get; set; }
}

And update your parent VM accordingly:

public class RegisterCoupleModel
{
   public PersonDetails GroomDetails { get; set; }
   public PersonDetails BrideDetails { get; set; }
}

Then you can provide the mapping from PersonDetails to User (or whatever type Groom.User is):

Mapper.CreateMap<PersonDetails,User>();

Note how i've got so explict property mapping -> because the fields have the same name in the source and destination, so no explicit mapping is required. Always try and do this where possible. Less code -> better code.

Then in addition to the above mapping, simply do this:

Mapper.CreateMap<RegisterCoupleModel, Couple>();

And AutoMapper will see that RegisterCoupleModel has two PersonDetails objects, see it already has a mapping definition, then automatically use that.

That should work (i've done it before).

You shouldn't always use flat viewmodels, nest them where necessary (such as reusing fields).

链接地址: http://www.djcxy.com/p/37386.html

上一篇: 使用Automapper映射只读字段

下一篇: 具有复杂类型的AutoMapper