AutoMapper映射从子类继承属性

时间:2015-09-28 18:39:12

标签: c# automapper

在我的数据中,我有两个可以拥有地址的实体。在数据库中,这些列在每个表中都是重复的。我可能会在将来规范化,但不想在此刻解决它。但是,在我的视图模型中,我确实将联系信息分解为一个可以重复使用的单独类。

我正试图找出一种在这种情况下映射属性的优雅方法。从数据库到视图模型的映射很容易,但我正在努力使用反向视图模型到数据库模型。

以下是数据实体类(简化了一点):

public abstract class EntityWithContactInfo
{
    [MaxLength(50)]
    public string Street1 { get; set; }

    [MaxLength(50)]
    public string Street2 { get; set; }

    [MaxLength(30)]
    public string City { get; set; }

    [MaxLength(30)]
    public string State { get; set; }

    [MaxLength(10)]
    public string Zip { get; set; }

    [MaxLength(10)]
    public string Phone { get; set; }

    [MaxLength(100)]
    public string Email { get; set; }
}

public class Organization : EntityWithContactInfo
{
    public int OrganizationId { get; set; }

    [MaxLength(100), Required]
    public string FullName { get; set; }

    [MaxLength(100), Required]
    public string DisplayName { get; set; }

    public string Website { get; set; }

    public string Information { get; set; }
}

public class Agent : EntityWithContactInfo
{
    public int AgentId { get; set; }

    [MaxLength(30), Required]
    public string LastName { get; set; }

    [MaxLength(20), Required]
    public string FirstName { get; set; }

    public string Comments { get; set; }
}

以下是我的观点模型(我还没有代理人 - 先在组织工作):

public class ContactInfoEditModel
{
    [StringLength(50)]
    [Display(Name = "Street Address 1")]
    public string Street1 { get; set; }

    [StringLength(50)]
    [Display(Name = "Street Address 2")]
    public string Street2 { get; set; }

    [StringLength(30)]
    public string City { get; set; }

    [StringLength(30)]
    public string State { get; set; }

    [StringLength(10)]
    public string Zip { get; set; }

    [Display(Name = "Pimary Phone")]
    public string Phone { get; set; }

    [StringLength(100)]
    [Display(Name = "Email Address")]
    public string Email { get; set; }
}

public abstract class EditModelBaseWithContactInfo
{
    [Display(Name = "Contact Information")]
    public ContactInfoEditModel ContactInfo { get; set; }
}

public class OrganizationEditModel : EditModelBaseWithContactInfo
{
    [Display(Name = "Id")]
    public int OrganizationId { get; set; }

    [Required, StringLength(100)]
    [Display(Name = "Full Name")]
    public string FullName { get; set; }

    [Required, StringLength(100)]
    [Display(Name = "Display Name")]
    public string DisplayName { get; set; }

    [Url(ErrorMessage = "Please enter a valid URL (including the protocol: http:// or https://).")]
    public string Website { get; set; }

    [UIHint("HtmlEditor")]
    [AllowHtml]
    public string Information { get; set; }
}

我现在对映射的看法是这样的:

Mapper.CreateMap<EntityWithContactInfo, ContactInfoEditModel>();

Mapper.CreateMap<Organization, OrganizationEditModel>()
      .MapEditModelBaseWithContactInfo();

Mapper.CreateMap<OrganizationEditModel, Organization>()
      .MapEntityWithContactInfo();


private static IMappingExpression<TEntity, TModel> MapEditModelBaseWithContactInfo<TEntity, TModel>(this IMappingExpression<TEntity, TModel> mapping)
    where TEntity : EntityWithContactInfo
    where TModel : EditModelBaseWithContactInfo
{
    return mapping.ForMember(m => m.ContactInfo, exp => exp.MapFrom(e => Mapper.Map<ContactInfoEditModel>(e)));
}

private static IMappingExpression<TModel, TEntity> MapEntityWithContactInfo<TModel, TEntity>(this IMappingExpression<TModel, TEntity> mapping)
    where TModel : EditModelBaseWithContactInfo
    where TEntity : EntityWithContactInfo
{
    return mapping.MapEntityModifiable()
                  .ForMember(e => e.Street1, exp => exp.MapFrom(m => m.ContactInfo.Street1))
                  .ForMember(e => e.Street2, exp => exp.MapFrom(m => m.ContactInfo.Street2))
                  .ForMember(e => e.City, exp => exp.MapFrom(m => m.ContactInfo.City))
                  .ForMember(e => e.State, exp => exp.MapFrom(m => m.ContactInfo.State))
                  .ForMember(e => e.Zip, exp => exp.MapFrom(m => m.ContactInfo.Zip))
                  .ForMember(e => e.Email, exp => exp.MapFrom(m => m.ContactInfo.Email))
                  .ForMember(e => e.State, exp => exp.MapFrom(m => m.ContactInfo.State))
                  .ForMember(e => e.Phone, exp => exp.MapFrom(m => m.ContactInfo.Phone));
}

我在静态映射类中创建了最后两个扩展方法,这样当我添加代理映射时,我不必复制.ForMember调用。如您所见,从数据模型到视图模型的映射看起来很好。然而,第二种扩展方法是我在努力的地方。它工作正常,但它似乎不是正确方式。正如您所看到的,我已明确列出了Organization / ContactInfo上的所有属性,即使它们都具有相同的名称(AutoMapper通常会自行处理)

似乎应该有一种方法告诉AutoMapper将Source的ContactInfo属性上的所有属性直接映射到Destination。有谁知道你是怎么做到的?我玩过Include&lt;&gt;和IncludeBase&lt;&gt;。

我还考虑让OrganizationEditModel直接从ContactInfoEditModel继承,但我不确定这是否会弄乱我的EditorTemplates(这仍然是一种解决方法,而不是正确的解决方案)。

1 个答案:

答案 0 :(得分:0)

查看ConvertUsing。第二种扩展方法可能如下所示:

private static IMappingExpression<TModel, TEntity> MapEntityWithContactInfo<TModel, TEntity>(this IMappingExpression<TModel, TEntity> mapping)
    where TModel : EditModelBaseWithContactInfo
    where TEntity : EntityWithContactInfo
{
    return mapping.MapEntityModifiable()
        .ConvertUsing(x => Mapper.Map<TEntity>(x.ContactInfo));
}