如何使用 ExpressMapper 映射递归嵌套对象
How to map recursive nested objects with ExpressMapper
我正在开发一个 Web 应用程序(首先是 EF6 代码),使用户能够填写评估。一个评价包含多个问题,一个问题包含多个子问题。
每个子问题都有一个 "mapping feature",使用户能够将一个子问题关联到另一个现有的子问题。
我有以下 Entity Framework 个模型(我删除了一些属性,因为我的示例不需要它们)
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();
}
一切都已映射并且工作正常,直到我在子问题 VM 中添加以下 属性:
public List<SubQuestionVM> SubquestionCurrentMapping { get; set; }
这 属性 创建一个多对多 table 到 link 的子问题一起用于映射功能。
当我尝试启动应用程序时,出现以下错误:
"Exception of type 'System.WhosebugException' was thrown."
我尝试的改变是:
在 SubquestionVM
//public List<SubQuestionVM> SubquestionCurrentMapping { get; set; }
public List<SubQuestionMappedVM> SubquestionCurrentMapping { get; set; } = new List<SubQuestionMappedVM>(); //Trying to fix by changing 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 回复 "A task was canceled."。
如果有人知道如何映射我的递归 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);
}
}
}
我正在开发一个 Web 应用程序(首先是 EF6 代码),使用户能够填写评估。一个评价包含多个问题,一个问题包含多个子问题。 每个子问题都有一个 "mapping feature",使用户能够将一个子问题关联到另一个现有的子问题。
我有以下 Entity Framework 个模型(我删除了一些属性,因为我的示例不需要它们)
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();
}
一切都已映射并且工作正常,直到我在子问题 VM 中添加以下 属性:
public List<SubQuestionVM> SubquestionCurrentMapping { get; set; }
这 属性 创建一个多对多 table 到 link 的子问题一起用于映射功能。
当我尝试启动应用程序时,出现以下错误:
"Exception of type 'System.WhosebugException' was thrown."
我尝试的改变是: 在 SubquestionVM
//public List<SubQuestionVM> SubquestionCurrentMapping { get; set; }
public List<SubQuestionMappedVM> SubquestionCurrentMapping { get; set; } = new List<SubQuestionMappedVM>(); //Trying to fix by changing 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 回复 "A task was canceled."。
如果有人知道如何映射我的递归 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);
}
}
}