【问题标题】:Automapper 6.0.2.0, Mapper.Map() throws StackOverflow when mapping Child EntitiesAutomapper 6.0.2.0,Mapper.Map() 映射子实体时抛出 StackOverflow
【发布时间】:2018-02-20 19:14:01
【问题描述】:

直截了当,我有以下模型:

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);

    }
}

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

我花了太多时间试图解决这个问题,老实说,我已经没有想法了。如果有人知道在这里做什么,我将不胜感激。 谢谢,提前和问候!

【问题讨论】:

  • 在我看来,您可以通过将此代码锐化到表明问题的最低限度来帮助您的事业。阅读关于提供minimal reproducible example

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


【解决方案1】:

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

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

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

【讨论】:

  • 确实是卢锡安,不需要那些成员。所以我必须摆脱它们。这里的问题是我错过了另一个需要保留其引用的映射配置文件,但这里没有提到,因为我错过了那部分,而这正是导致我所有问题的原因。但是非常感谢您的支持!!
【解决方案2】:

这里的问题是我缺少需要保留其引用的 另一个映射配置文件,但这里没有提到,因为我缺少那部分,那是导致我所有问题的那个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多