0

2 回目以降の呼び出し (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を使用するResolveUsingMapFrom、上記のopt =>ラムダで使用するかは問題ではありません。動作は同じです。つまり、以前の呼び出しからの値を再利用します。

AssessmentIdプロパティがソース タイプ ( ) に存在しませんElementAssessmentIdこのようにして、このコードがあるメソッドへの後続の呼び出し中に動的に「変更される可能性がある」値を割り当てようとします。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));

1 回目questionsは問題ありません。つまり、すべてのAssessmentQuestionViewModelオブジェクトのプロパティが定義AssessmentIdどおりに正しく設定されています。CreateMap

2回目の呼び出しから、1回目の呼び出しから再利用assessmentIdし、ビジネスロジックを台無しにします。これは、メソッドにパラメーターとして渡されているAssessmentId更新済みにマップすることを期待しているためです。assessmentIdList

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 に答える