0

我有一种情况,从第二次调用和后续调用(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,ResolveUsing还是MapFrom在上面的opt =>lambda 中都没有关系。行为是相同的,也就是说,它重用了先前调用的值。

AssessmentIdElement源类型 ( )中不存在属性。这样,我尝试分配AssessmentId一个在随后调用我拥有此代码的方法期间“可能”动态更改的值。assessmentId是我的 ASP.NET MVC 操作方法中的一个参数,如上面方法签名中所示。

List然后我在action 方法中调用这段代码:

var questions =
    Mapper.Map<IEnumerable<Element>, IEnumerable<AssessmentQuestionViewModel>>
     (Database.Elements.Where(e => !elementIds.Contains(e.ElementId) &&
                              e.Standard.ChapterId == chapterId));

第一次,没问题questions,也就是说,所有AssessmentQuestionViewModel对象都AssessmentId按照定义正确设置了属性CreateMap

从第 2 次调用开始,它重用了第 1 次assessmentId调用中的第一次调用,它搞乱了我的业务逻辑,因为我希望它映射AssessmentIdassessmentId作为参数传递给List方法的更新。

只是为了确定:我在代码中设置了一个断点,我可以看到assessmentId参数的值是正确的。只是返回的映射对象questions在属性中有错误的值AssessmentId- 一个与当前值不同的assessmentId值。据我了解,这些值应该相等,因为我要求 AutoMapper 使用该当前值进行映射。

我有 AutoMapper 2.2.1-ci9000(预发行版),但我用以前的版本对此进行了测试,我看到了同样的行为。我更新了售前赛,认为这种“不当行为”会消失。

我认为这是一个错误。如果我错了或者我试图以不受支持的方式使用它,请纠正我。:)

4

1 回答 1

4

我认为这里的问题是您尝试创建相同类型的多个映射 - AutoMapper 不支持。每次List调用您的操作时,您都会创建一个新映射(具有不同的ForMember(...)子句)。AutoMapper 不会抛出异常,它只是忽略重复的映射,所以您在这里看到的不是错误,而是预期的行为。

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;
}
于 2013-01-06T15:33:36.710 回答