簡體   English   中英

如何使用ExpressMapper映射遞歸嵌套對象

[英]How to map recursive nested objects with ExpressMapper

我正在開發一個Web應用程序(首先是EF6代碼),該應用程序使用戶能夠填寫評估。 評估包含多個問題,一個問題包含多個子問題。 每個子問題都有一個“映射功能”,使用戶可以將一個子問題與另一個現有子問題相關聯。

我有以下實體框架模型(我刪除了一些屬性,因為在我的示例中不需要這些屬性)

public class Question
{
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<SubQuestion> SubQuestions { get; set; }
}
public class SubQuestion
{
    public int ID { get; set; }
    public int QuestionID { get; set; }
    public virtual Question Question { get; set; }

    [Required]
    [MaxLength(255)]
    public string Name { get; set; }
    public virtual ICollection<Answer> Answers { get; set; }

    //These 2 properties are used to create a many-to-many table for the mapping of subquestions
    //Automatic name = SubQuestion_ID
    //Subquestion of current evaluation to map to another evaluation
    public virtual ICollection<SubQuestion> SubquestionCurrentMapping { get; set; }

    //Automatic name = SubQuestion_ID1
    //Subquestion of evaluation the current evaluation is mapped to
    public virtual ICollection<SubQuestion> SubquestionPreviousMapping { get; set; }

}

在項目中,我們使用以下DTO對象

public class QuestionVM
{
    public int ID { get; set; }
    public string Name { get; set; }
    public List<SubQuestionVM> SubQuestions { get; set; } = new List<SubQuestionVM>();
}

public class SubQuestionVM
{
    public int ID { get; set; }
    public int QuestionID { get; set; }
    public string Name { get; set; }
    public List<AnswerVM> Answers { get; set; }

    public List<SubQuestionVM> SubquestionCurrentMapping { get; set; }
}

我們正在使用ExpressMapper(請參閱http://expressmapper.org )。 我們有一種方法可以將所有DTO與EF模型進行映射,如下所示:

public void MappingRegistration()
{
    Mapper.Register<Question, QuestionVM>();
    Mapper.Register<SubQuestion, SubQuestionVM>();
    Mapper.Compile();
}

一切都已映射並且工作正常,直到我在subquestionVM中添加了以下屬性:

public List<SubQuestionVM> SubquestionCurrentMapping { get; set; }

此屬性創建一個多對多表,以將子問題鏈接在一起以實現映射功能。

當我嘗試啟動應用程序時,出現以下錯誤:

“引發了類型為'System.StackOverflowException'的異常。”


我嘗試過的更改是:在SubquestionVM中

//public List<SubQuestionVM> SubquestionCurrentMapping { get; set; }                                                                         
public List<SubQuestionMappedVM> SubquestionCurrentMapping { get; set; } = new List<SubQuestionMappedVM>(); //Trying to fix by changing vm

有我要測試的新VM:

public class SubQuestionMappedVM
{
    public int ID { get; set; }
    public int QuestionID { get; set; }
    public string Name { get; set; }
    //Remove this property, don't need more than 1 level of recursion anyway
    //public List<SubQuestionMappedVM> SubquestionCurrentMapping { get; set; }
    public List<AnswerVM> Answers { get; set; }
}

我還將新的VM添加到執行映射的方法中:

Mapper.Register<SubQuestion, SubQuestionMappedVM>();

我認為我的問題是因為我正在映射subquestionVM,其中包含創建遞歸的subquestionVM列表。 我正在嘗試創建其他subquestionVM來繞過該問題,但是我的網頁甚至沒有顯示在我的瀏覽器中。 漫長的1分鍾45分鍾后,Visual Studio響應“任務已取消”。

如果有人知道如何映射我的遞歸SubquestionVM,如何使用其他VM停止遞歸或任何其他防止堆棧溢出錯誤的解決方案,我將不勝感激!

這是我解決此問題的方法:

我不知道如何使用ExpressMapper或其他視圖模型來繞過堆棧溢出異常,因此我創建了一種方法,該方法可以將EF模型手動映射到DTO模型。

/// <summary>
/// Map list of SubquestionVM (SubquestionCurrentMapping) with data from current Component (EF model).
/// 
/// Why are we doing this?
///     Because when using the ExpressMapping to map 'SubQuestion' to 'SubQuestionVM', it creates a stack overflow error on the property 'SubquestionCurrentMapping'
///     which is caused by recursive VM.
///     I originaly tried alternative solution like:
///         changing 'List<SubQuestionVM>' for 'List<SubQuestionMappedVM>' but the website was not even loading (even with proper value in the new VM, and global.asax),
///         loading the faulty property later on, but any attempt to populate the object was resulting in an overflow at a moment or another.
///     Thankfully the manual mapping is proven to be effective and errorless!
/// </summary>
/// <param name="evaluationVM"></param>
/// <param name="component"></param>
private static void ManualMappingOfRecursiveSubquestionVM(CurrentEvaluationVM evaluationVM, Component component)
{
    foreach (var subquestion in component?.Question?.SubQuestions)
    {
        //Find corresponding subquestionVM and manually map them
        var subquestionVM = evaluationVM.CurrentComponent?.Question?.SubQuestions.Find(s => s.ID == subquestion.ID);

        foreach (var subquestionMapping in subquestion.SubquestionCurrentMapping.ToList())
        {
            var tempSubquestionVM = new SubQuestionVM
            {
                ID = subquestionMapping.ID,
                QuestionID = subquestionMapping.QuestionID,
                Name = subquestionMapping.Name,
                Clarification = subquestionMapping.Clarification,
                Description = subquestionMapping.Description,
                Index = subquestionMapping.Index,
                CanSelectGoal = subquestionMapping.CanSelectGoal,
                IsDate = subquestionMapping.IsDate,
                Deprecated = subquestionMapping.Deprecated,
                MultipleChoices = subquestionMapping.MultipleChoices.Map<ICollection<MultipleChoice>, List<MultipleChoiceVM>>(),
                Answers = subquestionMapping.Answers.Map<ICollection<Answer>, List<AnswerVM>>()
            };
            subquestionVM.SubquestionCurrentMapping.Add(tempSubquestionVM);
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM