Automapper 6.0.2.0,Mapper.Map()在映射子实体时抛出StackOverflow

时间:2018-02-20 19:14:01

标签: c# automapper stack-overflow automapper-6

直截了当地说,我有以下型号:

public abstract class ControlData
{
    public DateTime CreatedDate { get; set; }
    public int CreatedById { get; set; }
    [ForeignKey("CreatedById")]
    public Collaborator CreatedBy { get; set; }
    public DateTime? UpdatedDate { get; set; }
    public int? UpdatedById { get; set; }
    [ForeignKey("UpdatedById")]
    public Collaborator UpdatedBy { get; set; }
}

[Table("My_Position_Table")]
public class Position : ControlData
{
    [Key]
    [Column("PositionId")]
    public int Id { get; set; }
    [Column("PositionStatusId")]
    public int StatusId { get; set; }
    [ForeignKey("StatusId")]
    public PositionStatus Status { get; set; }
    public int OpportunityId { get; set; }


    [ForeignKey("OpportunityId")]
    public Opportunity Opportunity { get; set; }
    public int Total { get; set; }
    [Column("PositionDurationId")]
    public int DurationId { get; set; }
    [ForeignKey("DurationId")]
    public PositionDuration Duration { get; set; }
    public DateTime StartDate { get; set; }
    //TODO Agregar las otras propiedades con sus respectivos catalogos
    public string PracticeId { get; set; }
    [ForeignKey("PracticeId")]
    public Practice Practice { get; set; }
    public int RoleId { get; set; }
    [ForeignKey("RoleId")]
    public PersonRole Role { get; set; }
    public int PlatformId { get; set; }
    [ForeignKey("PlatformId")]
    public Platform Platform { get; set; }
    public int LevelId { get; set; }
    [ForeignKey("LevelId")]
    public Level Level { get; set; }
    public int EnglishLevelId { get; set; }
    [ForeignKey("EnglishLevelId")]
    public EnglishLevel EnglishLevel { get; set; }
    public string CountryId { get; set; }
    public int LocationId { get; set; }
    [ForeignKey("LocationId")]
    public Location Location { get; set; }
    public int? OfficeId { get; set; }
    public int OperationId { get; set; }
    [ForeignKey("OperationId")]
    public Person Operation { get; set; }
    public int? EvaluatorId { get; set; }
    [ForeignKey("EvaluatorId")]
    public Collaborator Evaluator { get; set; }
    public int? SourcerId { get; set; }
    [ForeignKey("SourcerId")]
    public Collaborator Sourcer { get; set; }
    public List<Candidate> Candidates { get; set; }
    public int? PositionCancellationReasonId { get; set; }
    [ForeignKey("PositionCancellationReasonId")]
    public PositionCancellationReason CancellationReason { get; set; }
    public string CancellationComments { get; set; }
    public int? CancellationById { get; set; }
    [ForeignKey("CancellationById")]
    public Collaborator CancellationBy { get; set; }
    public DateTime? CancellationDate { get; set; }
    public bool Active { get; set; }
    public bool WhereAvailable { get; set; }
    public bool RequestAsset { get; set; }
    public string CityZone { get; set; }
    public string TravelsTo { get; set; }
    public string Description { get; set; }
    public string SpecificationFile { get; set; }
    public int PositionPriorityId { get; set; }
    public int? SourcingGroupId { get; set; }
}

[Table("My_Opportunity_Table")]
public class Opportunity : ControlData
{
    [Column("OpportunityId")]
    [Key]
    public int Id { get; set; }
    [Column("OpportunityStatusId")]
    public int StatusId { get; set; }
    [ForeignKey("StatusId")]
    public OpportunityStatus Status { get; set; }
    public string ProjectId { get; set; }
    [ForeignKey("ProjectId")]
    public Project Project { get; set; }
    public string MarketId { get; set; }
    [ForeignKey("MarketId")]
    public Market Market { get; set; }
    public string CustomerId { get; set; }
    [ForeignKey("CustomerId")]
    public Customer Customer { get; set; }
    public string Name { get; set; }
    [Column("OpportunityTypeId")]
    public int TypeId { get; set; }
    [ForeignKey("TypeId")]
    public OpportunityType Type { get; set; }
    [Column("OpportunityPriorityId")]
    public int PriorityId { get; set; }
    [ForeignKey("PriorityId")]
    public OpportunityPriority Priority { get; set; }
    public int? OpportunityCancellationReasonId { get; set; }
    [ForeignKey("OpportunityCancellationReasonId")]
    public OpportunityCancellationReason CancellationReason { get; set; }
    public string CancellationComments { get; set; }
    public int? CancellationById { get; set; }
    [ForeignKey("CancellationById")]
    public Collaborator CancellationBy { get; set; }
    public DateTime? CancellationDate { get; set; }
    public bool Active { get; set; }        
    public List<OpportunityRole> OpportunityRoles { get; set; }
    public List<Position> Positions { get; set; }

}

而且,我已经在DTO中找到了他们的等价物:

public abstract class ControlDataDTO
{

    public DateTime CreatedDate { get; set; }
    public int CreatedById { get; set; }
    public CollaboratorPlainDTO CreatedBy { get; set; }
    public DateTime? UpdatedDate { get; set; }
    public int? UpdatedById { get; set; }
    public CollaboratorPlainDTO UpdatedBy { get; set; }
}

public class PositionDTO: ControlDataDTO
{

    public int Id { get; set; }
    public int StatusId { get; set; }
    public PositionStatusDTO Status { get; set; }
    public int OpportunityId { get; set; }
    public OpportunityDTO Opportunity { get; set; }
    public int Total { get; set; }
    public int DurationId { get; set; }
    public PositionDurationDTO Duration { get; set; }
    public DateTime StartDate { get; set; }
    public string PracticeId { get; set; }
    public PracticeDTO Practice { get; set; }
    public int RoleId { get; set; }
    public PersonRoleDTO Role { get; set; }
    public int PlatformId { get; set; }
    public PlatformDTO Platform { get; set; }
    public int LevelId { get; set; }
    public LevelDTO Level { get; set; }
    public int EnglishLevelId { get; set; }
    public EnglishLevelDTO EnglishLevel { get; set; }
    public string CountryId { get; set; }
    public int LocationId { get; set; }
    public LocationDTO Location { get; set; }
    public int? OfficeId { get; set; }
    public int OperationId { get; set; }
    public PersonDTO Operation { get; set; }
    public string OperationIS { get; set; }
    public bool WhereAvailable { get; set; }
    public bool RequestAsset { get; set; }
    public string CityZone { get; set; }
    public string TravelsTo { get; set; }
    public string Description { get; set; }
    public int CandidatesAccepted { get; set; }
    public int CandidatesRejected { get; set; }
    public int CandidatesWaiting { get; set; }
    public bool HasCandidatesWaiting { get; set; }
    public int TotalCandidates { get; set; }
    public string SpecificationFile { get; set; }
    public int? EvaluatorId { get; set; }
    public int? SourcerId { get; set; }
    public CollaboratorDTO Sourcer { get; set; }
    public int? SourcingGroupId { get; set; }
    public PositionCancellationReasonDTO CancellationReason { get; set; }
}

public class OpportunityDTO: ControlDataDTO
{

    public int Id { get; set; }
    public int StatusId { get; set; }
    public OpportunityStatusDTO Status { get; set; }
    public string ProjectId { get; set; }
    public ProjectDTO Project { get; set; }
    public string MarketId { get; set; }
    public MarketDTO Market { get; set; }
    public string CustomerId { get; set; }
    public CustomerDTO Customer { get; set; }
    public string Name { get; set; }
    public int TypeId { get; set; }
    public OpportunityTypeDTO Type { get; set; }
    public int PriorityId { get; set; }
    public OpportunityPriorityDTO Priority { get; set; }
    public int? OpportunityCancellationReasonId { get; set; }
    public OpportunityCancellationReasonDTO CancellationReason { get; set; }
    public string CancellationComments { get; set; }
    public int? CancellationById { get; set; }
    public CollaboratorPlainDTO CancellationBy { get; set; }
    public DateTime? CancellationDate { get; set; }
    public CollaboratorDTO Responsible { get; set; }
    public List<OpportunityRoleDTO> OpportunityRoles { get; set; }
    public int TotalPositions { get; set; }
    public bool CandidatesWarning { get; set; }
    public bool Active { get; set; }
    public List<PositionDTO> Positions { get; set; }
}

对于这种映射初始化,我们使用Profiles,就像这样:

public class AutoMapperConfig
{
    public static void RegisterMappings()
    {
        Mapper.Initialize(cfg =>
        {
            // ...
            cfg.AddProfile<OpportunityMappingProfile>();
            // ...
        });
    }
}

public class OpportunityMappingProfile : Profile
{
    public OpportunityMappingProfile()
    {
        CreateMap<Opportunity, OpportunityDTO>()
            .ForMember(x => x.Responsible, x => x.MapFrom(c => GetFromOpportunityRoles(c.OpportunityRoles, Constants.OpportunityResponsible)))
            .ForMember(x => x.TotalPositions, x => x.MapFrom(c => c.Positions.Count()))
            .ForMember(x => x.CandidatesWarning, x => x.MapFrom(c => c.Positions.Count() > 0 ? 
                c.Positions.Any(pos => pos.Candidates.Any(cand => cand.StatusId == 3)) : 
                false))
            .ForMember(x => x.CreatedBy, x => x.MapFrom(c => Mapper.Map<CollaboratorPlainDTO>(c.CreatedBy)))
            .ForMember(x => x.UpdatedBy, x => x.MapFrom(c => Mapper.Map<CollaboratorPlainDTO>(c.UpdatedBy)))
            .ForMember(x => x.Positions, x => x.MapFrom(c => Mapper.Map<List<PositionDTO>>(c.Positions))).PreserveReferences(); --> Even using this method, StackOverflow exception is still occurring...
        CreateMap<OpportunityDTO, Opportunity>()
            .ForMember(x => x.CancellationReason, x => x.Ignore())
            .ForMember(x => x.CreatedBy, x => x.Ignore())
            .ForMember(x => x.UpdatedBy, x => x.Ignore())
            .ForMember(x => x.Positions, x => x.Ignore());
    }

    private Collaborator GetFromOpportunityRoles(List<OpportunityRole> opportunityRoles, string rol)
    {
        var opportunityRole = opportunityRoles.FirstOrDefault(opp => opp.ProjectRoleTypeId == rol);
        return opportunityRoles != null ? opportunityRole.Collaborator : null;
    }
}

最后,执行映射的逻辑我得到了注释错误......

public class OpportunityLogic : IOpportunityLogic
{
    // Properties...

    public OpportunityLogic(parameters list here, though irrelevant for this example)
    {
        // ...
    }

    public ActionResponse<List<OpportunityDTO>> GetOpportunitiesWithPositions(int personId)
    {
        // Information is retrieved from DB, here...
        List<Opportunity> listOpportunities = opportunityRepository.Get(                
            opp => opp.Status,
            opp => opp.Market,
            opp => opp.Customer,
            opp => opp.Type,
            opp => opp.Project,
            opp => opp.Status,
            opp => opp.Positions,
            opp => opp.Positions.Select(pos => pos.Candidates),
            opp => opp.Positions.Select(pos => pos.Status),
            opp => opp.Positions.Select(pos => pos.Practice),
            opp => opp.Positions.Select(pos => pos.Role),
            opp => opp.Positions.Select(pos => pos.Platform),
            opp => opp.Positions.Select(pos => pos.Sourcer));

        // After having retrieved data, here I re-define my model.
        listOpportunities = listOpportunities
            .Where( opp => opp.StatusId == (int)Constants.OpportunityStatus.Open &&
                           opp.Active == true &&
                           opp.Positions.Any(pos => pos.StatusId == (int)Constants.PositionStatus.Open &&
                                                    pos.Candidates.Any(can => can.PersonId == personId &&
                                                                              can.Active == true &&
                                                                              (can.StatusId == (int)Constants.CandidateStatus.Lead || 
                                                                               can.StatusId == (int)Constants.CandidateStatus.Waiting))))
            .ToList();

        // MY PROBLEM IS HERE....
        var mappedOpportunities = Mapper.Map<List<OpportunityDTO>>(listOpportunities);            

        return new ActionResponse<List<OpportunityDTO>> (mappedOpportunities);

    }
}

我的问题在尝试将我的模型(列表)映射到DTO(列表)时开始;错误是众所周知的&#34; StackOverflow异常&#34;。如果我使用&#34; PreserveReferences()&#34;方法,为什么仍然抛出相同的异常?在尝试了不同的深度级别(1,2,3 ...)之后,&#34; MaxDepth()方法&#34;也是如此。

我花了太多时间试图解决这个问题,说实话,我已经没有想法了。如果有人知道该怎么做,我会非常感激。 谢谢,推进&amp;问候!!

2 个答案:

答案 0 :(得分:0)

从6.1.0开始只要可以静态检测递归,就会在配置时自动设置PreserveReferences。如果在您的情况下没有发生这种情况,请使用完整的repro打开一个问题,我们会调查它。

http://automapperdocs.readthedocs.io/en/latest/5.0-Upgrade-Guide.html#circular-references

但是你必须删除MapFroms中的Map调用。那些ForMember-s不需要。

答案 1 :(得分:0)

这里的问题是我缺少需要保留其引用的 另一个Mapping Profile ,但是这里没有提到,因为我错过了那部分,那是导致我所有问题的那个。