9

特定のマッピングを一時的に停止するように AutoMapper を「説得」できますか?

何を達成しようとしているのかを説明するために、イラストを使用します。LINQ を使用して、Students、Courses、Activities、Clubs などのデータベース オブジェクト (テーブル) とやり取りするリポジトリStudentRepositoryがあるとします。アプリケーション側には、一致するドメイン オブジェクト Student、Course、Activity、Club があります。Student クラスには、次のような Course、Activity、および Club 型の配列メンバーが含まれています。

public class Student
{
    // ... more members
    public Course[] Courses { get; set; }
    public Activity[] Activities { get; set; }
    public Club[] Clubs { get; set; }
    // ... even more members
}

AutoMapper は、次のように StudentRepository の静的コンストラクターでマッピングが定義されているドメイン オブジェクトにデータベース オブジェクトをマップするように構成されています。

public class StudentRepository : IStudentRepository
{
    static class StudentRepository
    {
        // ... other mappings

        Mapper.CreateMap<TableStudent, Student>()
            .ForMember(dest => dest.Courses, opt => opt.MapFrom(src => Mapper.Map<IEnumerable<Course>>(src.TableCourses)))
            .ForMember(dest => dest.Activities, opt => opt.MapFrom(src => Mapper.Map<IEnumerable<Activity>>(src.TableActivities)))
            .ForMember(dest => dest.Clubs, opt => opt.MapFrom(src => Mapper.Map<IEnumerable<Clubs>>(src.TableClubs)))
        // where TableStudents, TableCourses, TableActivities, TableClubs are database entities

        // ... yet more mappings

    }
}

1 つの関数ブロック内でマッピングを一時停止するように AutoMapper を「説得」することは可能ですか? 例えば:

public Student[] GetStudents()
{
    DataContext dbContext = new StudentDBContext();

    var query = dbContext.Students;
    // => SUSPEND CONFIGURATION MAPPINGS for Subjects, Activities and Clubs WHILE STILL making use of others
    // => The idea here it to take personal charge of 'manually' setting the particular members (*for some specific reasons)

    var students = Mapper.Map<Student>(query); // => Still be able to use AutoMapper to map other members
}

public Student[] OtherStudentRepositoryMethods()
{
    // Other repository methods continue to make use of the mappings configured in the static constructor
}

注「特定の理由で」: AutoMapperから制御を奪いたい理由の 1 つは、これです。to-break-down-in-more-advanced-scenarios/ 1:n アソシエーションの場合、LINQ to SQL はクエリごとに 1 つの 1:n アソシエーションの参加のみをサポートします。AutoMapper はここでは非効率的です。返された N 人の学生の Courses を読み込むために N 回の呼び出しを行い、同じ N 人の学生のために Activity を読み込むためにさらに N 回の呼び出しを行い、返された同じ N 人の学生のために Clubs を読み込むためにさらに N 回の呼び出しを行う可能性があります。

4

3 に答える 3

4

1 つの関数ブロック内でマッピングを一時停止するように AutoMapper を「説得」することは可能ですか?

私が知っているように、それを行う最良の方法-このように Ignore() を使用します

public class StudentRepository : IStudentRepository
{
    static class StudentRepository
    {
        // ... other mappings

        Mapper.CreateMap<TableStudent, Student>()
            .ForMember(dest => dest.Courses, opt => opt.Ignore())
            .ForMember(dest => dest.Activities, opt => opt.Ignore())
            .ForMember(dest => dest.Clubs, opt => opt.Ignore())
        // where TableStudents, TableCourses, TableActivities, TableClubs are database entities

        // ... yet more mappings

    }
}

また、以前に気がついたように、達成したい目標ごとに異なるプロファイルを使用することをお勧めします。例を次に示します。

public BaseService()
{
    AutoMapperRegistry.Configure();
}

public class AutoMapperRegistry
{
    public static void Configure()
    {
        Mapper.Initialize(x =>
        {
            x.AddProfile<ServiceProfile1>();
            x.AddProfile<ServiceProfileReverseProfile1>();
        });
    }
}

public class ServiceProfile1 : Profile
{
    protected override string ProfileName
    {
        get
        {
            return "ServiceProfile1";
        }
    }

    protected override void Configure()
    {
        Mapper.CreateMap<DataContract_Sub, DTO_Sub>();
        Mapper.CreateMap<DataContract, DTO>()
            .ForMember(x => x.DataContract_Sub, opt => opt.MapFrom(y => y.DTO_Sub))
    .BeforeMap((s, d) => 
            {
                // your custom logic
            })
    .AfterMap((s, d) => 
            {
                // your custom logic
            });
    }
}
于 2012-05-28T09:37:27.897 に答える
2

これを実現する 1 つの方法は、シナリオごとに個別のマッピング エンジン インスタンスを作成することです。これにより、単一のタイプをさまざまな方法でマッピングしたいというジミー ボガードの回答で提案されているように、さまざまなマップを構成できます。

于 2012-05-28T08:58:26.897 に答える
0

うーん...フィードバックをありがとう。私は時間をかけてすべての回答と提案を検討しました。それらは多くの思考の材料を提供しましたが、特に正確にレンダリングするものはありません. 私が試したものを注入する必要があると思いました。(免責事項:私の意見では、それは汚いアプローチであり、多くのことがうまくいかない可能性があり、マーフィーの法則は引き続き保持されます)。特定のインスタンスで無視機能を利用して、マッピングを「一時停止」できます。通常、次のように try および catch ブロックで:

public Student[] GetStudents()
{
    try
    { // Suspend/Ignore the mappings
        // => SUSPEND CONFIGURATION MAPPINGS for Subjects, Activities and Clubs
        Mapper.CreateMap<TableStudent, Student>()
                    .ForMember(dest => dest.Courses, opt => opt.Ignore())
                    .ForMember(dest => dest.Activities, opt => opt.Ignore())
                    .ForMember(dest => dest.Clubs, opt => opt.Ignore())

        DataContext dbContext = new StudentDBContext();

        var query = dbContext.Students;

        // other logic ...

        var students = Mapper.Map<Student>(query); // => Still be able to use AutoMapper to map other members
        // set the properties you needed to do manually
    }
    finally // Restore back the mappings
    {
        Mapper.CreateMap<TableStudent, Student>()
                    .ForMember(dest => dest.Courses, opt => opt.MapFrom(src => Mapper.Map<IEnumerable<Course>>(src.TableCourses)))
                    .ForMember(dest => dest.Activities, opt => opt.MapFrom(src => Mapper.Map<IEnumerable<Activity>>(src.TableActivities)))
                    .ForMember(dest => dest.Clubs, opt => opt.MapFrom(src => Mapper.Map<IEnumerable<Clubs>>(src.TableClubs)))
    }
}

私が言ったように、おそらく汚れています。私が喜んで書くようなコードではありません-特に、CreateMap()がfinallyブロック内で失敗した場合にどのような例外的な状況が発生するかわからないため、アプローチをオーバーホールできないレガシーアプリケーションでは-上記の@AndriyZakharkoで提案されているような異なるプロファイルを使用する可能性があります。それを使用して、一時的に制御を取り戻すことができます。個人的にやってみました。

于 2012-06-04T08:46:26.543 に答える