如何使用Automapper将派生类映射到基类属性

时间:2017-01-30 21:38:20

标签: c# entity-framework-6 automapper

首先,如果我的上述问题令人困惑,我对使用Automapper都不熟悉,并且不太了解这种语言并且很少提出这样的问题,所以我可能会试着说清楚我的问题。想到一个荒谬的问题。

我创建了一些从基类继承的类,因为我打算重新使用基类来实现比下面显示的实体更多的实体。为简单起见,我将保持类的属性无效。

我的问题是PersonBusiness属性的映射。当我使用EF 6从SQL加载数据时,我看到它将PersonBusiness对象的Person和Business属性作为Employee对象和Branch对象加载,因为这是我为查询提取的内容,但是当我尝试映射时Employee Object和Branch对象从PersonBusiness对象到PersonBusinessDto对象,它将它们作为Person和Business类类型加载;显然,不包括派生类中包含的所有属性。

很明显,鉴于加载到PersonBusiness对象中的数据,Person和Business属性是可以使用派生类型Employee和Branch加载的对象引用变量,但出于某种原因,Automapper会看到Employee和Branch对象并且只将它们映射到Person and Business的基本类型。

这是从数据库加载的数据的示例:

This is an example of the data loaded from the database

这是映射到PersonBusinessDto的数据示例:

And this is an example of the data mapped to the PersonBusinessDto

下面是我用来将实体映射到DTO的基本类结构和映射,除了PersonBusiness映射之外,它们可以正常工作。

Entity.cs

public abstract class Entity : IEntity
{

}

EntityDto.cs

public abstract class EntityDto : IEntityDto
{

}

Person.cs

public abstract class Person : Entity
{
    public List<PersonBusiness> PersonBusinesses { get; set; };
}

PersonDto.cs

public abstract class PersonDto : EntityDto
{
    public List<PersonBusinessDto> PersonBusinesses { get; set; };
}

Employee.cs

public class Employee : Person
{

}

EmployeeDto.cs

public class EmployeeDto : PersonDto
{

}

Business.cs

public abstract class Business : Entity
{
    public List<PersonBusiness> PersonBusinesses { get; set; };
}

BusinessDto.cs

public abstract class BusinessDto : EntityDto
{
    public List<PersonBusinessDto> PersonBusinesses { get; set; };
}

Branch.cs

public class Branch : Business
{

}

BranchDto.cs

public class BranchDto : BusinessDto
{

}

PersonBusiness.cs

public class PersonBusiness
{
    public int PersonId { get; set; }
    public int BusinessId { get; set; }
    public Enums.RoleType RoleType { get; set; }

    public Person Person { get; set; }
    public Business Business { get; set; }
}

PersonBusinessDto.cs

public class PersonBusinessDto
{
    public int PersonId { get; set; }
    public int BusinessId { get; set; }
    public Enums.RoleType RoleType { get; set; }

    public PersonDto Person { get; set; }
    public BusinessDto Business { get; set; }
}

AutoMapperConfig.cs

public class ProfileMapping
        : Profile
    {
        private readonly IMapperConfiguration _mappingConfiguration;

        public ProfileMapping(IMapperConfiguration config)
        {
            _mappingConfiguration = config;
        }

        protected override void Configure()
        {
            _mappingConfiguration.AllowNullDestinationValues = true;

            _mappingConfiguration
                .CreateMap<Person, PersonDto>()
                .ForMember(dto => dto.PersonBusinesses, opt => opt.MapFrom(src => src.PresonBusinesses));

            _mappingConfiguration
                .CreateMap<Employee, EmployeeDto>()

            _mappingConfiguration
                .CreateMap<Business, BusinessDto>()
                .ForMember(dto => dto.PersonBusinesses, opt => opt.MapFrom(src => src.PresonBusinesses));

            _mappingConfiguration
                .CreateMap<Branch, BranchDto>();

            _mappingConfiguration
                .CreateMap<PersonBusiness, PersonBusinessDto>()
                .ForMember(dto => dto.Business, opt => opt.MapFrom(src => src.Business))
                .ForMember(dto => dto.Person, opt => opt.MapFrom(src => src.Person));
        }
    }

1 个答案:

答案 0 :(得分:0)

这里发生的事情是,EmployeeBranch分别被提升为PersonBusiness,因为这些是PersonBusiness类中的实际类型。然后,当AutoMapper执行映射时,它会看到PersonBusiness类型,因此会根据配置将它们映射到PersonDtoBusinessDto

对象仍然是EmployeeBranch的实例,即使它们已被上升后也是如此;你可以回到EmployeeBranch。但是,AutoMapper正在创建PersonDtoBusinessDto的实际实例,因此无法将这些实例投射到EmployeDtoBranchDto

如果没有一个具有实际正确属性类型的类,则必须在映射期间将它们转换回正确的类型,这将是一个真正的痛苦。原则上,您将遇到MapFrom无法返回不同派生类型的问题,因为lambda只能返回一种类型。

AutoMapper提供了一些guidance来说明如何使这种事情发挥作用。但是,您会注意到它直接处理实例,而不是那些实例上的属性。我不确定如何实际执行您需要做的事情,而不是在从PersonBusiness映射到PersonBusinessDto时忽略映射这些属性,然后使用方法显式映射属性AutoMapper详细介绍了文档,即

personBusinessDto.Person = Mapper.Map(personBusiness.Person, personBusiness.Person.GetType(), typeof(PersonDto));
像我说的那样:真正的痛苦。