C# 如何使用ExpressMapper映射递归嵌套对象

C# 如何使用ExpressMapper映射递归嵌套对象,c#,entity-framework-6,express-mapper,C#,Entity Framework 6,Express Mapper,我正在开发一个web应用程序(EF6代码优先),它允许用户填写评估。一个评估包含多个问题,一个问题包含多个子问题。 每个子问题都有一个“映射功能”,使用户可以将一个子问题与另一个现有子问题相关联 我有以下实体框架模型(我删除了一些属性,因为我的示例不需要它们) 公开课问题 { 公共int ID{get;set;} 公共字符串名称{get;set;} 公共虚拟ICollection子问题{get;set;} } 公共类子问题 { 公共int ID{get;set;} public int Ques

我正在开发一个web应用程序(EF6代码优先),它允许用户填写评估。一个评估包含多个问题,一个问题包含多个子问题。 每个子问题都有一个“映射功能”,使用户可以将一个子问题与另一个现有子问题相关联

我有以下实体框架模型(我删除了一些属性,因为我的示例不需要它们)

公开课问题
{
公共int ID{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection子问题{get;set;}
}
公共类子问题
{
公共int ID{get;set;}
public int QuestionID{get;set;}
公共虚拟问题{get;set;}
[必需]
[最大长度(255)]
公共字符串名称{get;set;}
公共虚拟ICollection)。我们有一种方法,可以使用EF模型映射所有DTO,如下所示:

public void MappingRegistration()
{
    Mapper.Register<Question, QuestionVM>();
    Mapper.Register<SubQuestion, SubQuestionVM>();
    Mapper.Compile();
}
public void映射注册()
{
Register()映射器;
Register()映射器;
Compile();
}
在我在subquestionVM中添加以下属性之前,一切都已映射并正常工作:

public List<SubQuestionVM> SubquestionCurrentMapping { get; set; }
publicslist子问题currentmapping{get;set;}
此属性创建多对多表,以将映射功能的子问题链接在一起

尝试启动应用程序时,出现以下错误:

“引发了类型为'System.StackOverflowException'的异常。”


我尝试的改变是: 在子问题中

//public List<SubQuestionVM> SubquestionCurrentMapping { get; set; }                                                                         
public List<SubQuestionMappedVM> SubquestionCurrentMapping { get; set; } = new List<SubQuestionMappedVM>(); //Trying to fix by changing vm
//公共列表子问题currentmapping{get;set;}
public List SubquestionCurrentMapping{get;set;}=new List();//试图通过更改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; }
}
公共类子问题MappedVM
{
公共int ID{get;set;}
public int QuestionID{get;set;}
公共字符串名称{get;set;}
//删除此属性,无论如何不需要超过1级的递归
//公共列表子问题CurrentMapping{get;set;}
公共列表答案{get;set;}
}
我还将新VM添加到进行映射的方法中:

Mapper.Register<SubQuestion, SubQuestionMappedVM>();
Mapper.Register();
我想我的问题是因为我正在映射一个子问题VM,其中包含一个创建递归的子问题VM列表。我试图创建一个不同的子问题VM来绕过这个问题,但我的网页甚至没有显示在我的浏览器中。经过长时间的1分钟45后,Visual Studio以“任务被取消”作为响应


如果有人知道如何映射我的递归子问题VM、如何使用不同的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);
        }
    }
}
//
///使用当前组件(EF模型)的数据映射子问题VM(子问题CurrentMapping)列表。
/// 
///我们为什么要这样做?
///因为使用ExpressMapping将“SubQuestion”映射到“SubQuestionVM”时,会在属性“SubquestionCurrentMapping”上创建堆栈溢出错误
///这是由递归VM引起的。
///我最初尝试过其他解决方案,如:
///将“列表”更改为“列表”,但网站甚至没有加载(即使在新VM和global.asax中具有适当的值),
///稍后加载错误的属性,但任何填充对象的尝试都会在某个时刻导致溢出。
///谢天谢地,手动映射被证明是有效和无错误的!
/// 
/// 
/// 
私有静态无效手动映射递归子问题VM(CurrentEvaluationVM evaluationVM,组件)
{
foreach(组件中的var子问题?.问题?.子问题)
{
//找到相应的子问题VM并手动映射它们
var subquestionVM=evaluationVM.CurrentComponent?.Question?.SubQuestions.Find(s=>s.ID==subquestion.ID);
foreach(子问题中的var subquestionMapping.SubquestionCurrentMapping.ToList())
{
var tempSubquestionVM=新的子问题vm
{
ID=subquestionMapping.ID,
QuestionID=子QuestionMapping.QuestionID,
Name=子问题映射。Name,
澄清=子问题映射。澄清,
Description=子问题映射。Description,
索引=子问题映射。索引,
CanSelectGoal=子问题映射。CanSelectGoal,
IsDate=子问题映射。IsDate,
弃用=子问题映射。弃用,
MultipleChoices=subquestionMapping.MultipleChoices.Map(),
答案=子问题映射。答案。映射()
};
subquestionVM.SubquestionCurrentMapping.Add(tempSubquestionVM);
}
}
}

以下是我解决此问题的方法:

我不知道如何使用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);
        }
    }
}
//
///使用当前组件(EF模型)的数据映射子问题VM(子问题CurrentMapping)列表。
/// 
///我们为什么要这样做?
///因为使用ExpressMapping将“SubQuestion”映射到“SubQuestionVM”时,会在属性“SubquestionCurrentMapping”上创建堆栈溢出错误
///这是由递归VM引起的。
///我最初尝试过其他解决方案,如:
///将“列表”更改为“列表”,但网站甚至没有加载(即使在新VM和global.asax中具有适当的值),
///稍后加载错误属性,但任何填充尝试
/// <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);
        }
    }
}