我遇到的情况是从第二个调用和后续调用(Ajax GET调用)开始,AutoMapper
正在重用前一个值(来自操作链接中单击的第一个调用的值)。这就像是一个“缓存”问题......
public virtual ActionResult List(int assessmentId, int? chapterId, bool? isMenuClick)
{
Mapper.CreateMap<Element, AssessmentQuestionViewModel>().
ForMember(dest => dest.AssessmentId, opt => opt.MapFrom(e => assessmentId));
...
}
如果我在上述UseValue
lambda中使用ResolveUsing
,MapFrom
或opt =>
,则无关紧要。行为是相同的,也就是说,它重用以前调用的值。
AssessmentId
)中不存在 Element
属性。通过这种方式,我尝试在后续调用我拥有此代码的方法时为AssessmentId
分配一个“可能”动态更改的值。 assessmentId
是我的ASP.NET MVC操作方法中的一个参数,如上面方法签名中所示。
然后我在List
操作方法中调用此代码:
var questions =
Mapper.Map<IEnumerable<Element>, IEnumerable<AssessmentQuestionViewModel>>
(Database.Elements.Where(e => !elementIds.Contains(e.ElementId) &&
e.Standard.ChapterId == chapterId));
第一次,questions
没问题,也就是说,所有AssessmentQuestionViewModel
个对象都按照定义的AssessmentId
正确设置了CreateMap
属性。
从第二个电话开始,它会重复使用第一个电话中的assessmentId
并且它与我的业务逻辑混淆,因为我希望它将AssessmentId
映射到正在更新的assessmentId
作为参数传递给List
方法。
只是为了确定:我在代码中设置了一个断点,我可以看到assessmentId
参数的值是正确的。它只是返回的映射对象questions
,它在AssessmentId
属性中具有错误的值 - 一个与当前assessmentId
值不同的值。因为我要求AutoMapper使用当前值进行映射,所以这些值应该是我理解的。
我有AutoMapper 2.2.1-ci9000(预发布),但我用之前的版本测试了这个,我看到了同样的行为。我更新了Prerelease,认为这种“不良行为”会消失。
我认为这是一个错误。如果我错了或者我试图以不支持的方式使用它,请纠正我。 :)
答案 0 :(得分:4)
我认为你在尝试创建相同类型的多个映射时遇到问题 - 这是AutoMapper不支持的。每次调用List
操作时,都会创建一个新映射(具有不同的ForMember(...)
子句)。 AutoMapper不会抛出异常,只会忽略重复的映射,所以你在这里看到的不是bug,它是预期的行为。
ForMember
实际上是在每个地图上调用的,但是,这里有一个范围问题,因为您的变量被硬编码到表达式中。作为一种解决方法,你可以做类似的事情:
public class MyController
{
public MyController()
{
// define mapping once, but make assessment expression dynamic
Mapper.CreateMap<Element, AssessmentQuestionViewModel>().
ForMember(dest => dest.AssessmentId, opt => opt.MapFrom(e => GetCurrentAssessmentId()));
}
private int GetCurrentAssessmentId()
{
return (int)TempData["AssessmentId"];
}
public ActionResult List(int assessmentId, ...)
{
// store current assessment temporarily
TempData.Add("AssessmentId", assessmentId);
// execute mapping
var questions = Mapper.Map<IEnumerable<Element>, IEnumerable<AssessmentQuestionViewModel>>
(Database.Elements.Where(e => !elementIds.Contains(e.ElementId) &&
e.Standard.ChapterId == chapterId));
}
}
我会说,为了实现这一目标,你需要通过大量的工作,在没有AutoMapper帮助的情况下手动设置属性会更简单。
var questions = Mapper.Map<IEnumerable<Element>, IEnumerable<AssessmentQuestionViewModel>>(...);
foreach (var q in questions)
{
q.AssessmentId = assessmentId;
}