【问题标题】:AutoMapper map inherited properties from subclassAutoMapper 映射从子类继承的属性
【发布时间】:2015-09-28 18:39:11
【问题描述】:

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

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

以下是数据实体类(稍微简化):

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 和 IncludeBase。

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

【问题讨论】:

    标签: c# automapper


    【解决方案1】:

    查看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));
    }
    

    【讨论】:

    • 我试过了,它需要从 ContactInfoEditModel 到组织的映射(所有组织特定字段的 Ignore() 子句),但现在映射没有复制 any 从视图模型到数据模型的数据。
    猜你喜欢
    • 1970-01-01
    • 2017-03-13
    • 1970-01-01
    • 2021-04-30
    • 1970-01-01
    • 2021-02-27
    • 2020-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多