AutoMapper可以“说服”暂时暂停特定的映射吗?

时间:2012-05-22 14:37:34

标签: c# linq linq-to-sql automapper

可以“说服”AutoMapper暂时暂停特定映射吗?

为了说明我想要完成什么,我将使用一个插图。假设我有一个存储库 StudentRepository ,它使用LINQ与学生,课程,活动,俱乐部等数据库对象(表)进行交互。在应用程序端,有匹配的域对象Student,Course ,活动,俱乐部。 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

    }
}

是否有可能“说服”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中取出控制权的一个原因是http://codebetter.com/davidhayden/2007/08/06/linq-to-sql-query-tuning-appears-to-break-down-in-more-advanced-scenarios/,其中在1:n关联的情况下,LINQ to SQL仅支持每个查询加入一个1:n关联。 AutoMapper在这里效率低下 - 让N个学生返回加载课程的N个调用,N个学生返回的N个调用加载活动,并且可能还有N个调用加载俱乐部以返回相同的N个学生。

3 个答案:

答案 0 :(得分:4)

  

是否有可能“说服”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
            });
    }
}

答案 1 :(得分:2)

实现这一目标的一种方法是为每个场景创建单独的映射引擎实例,这样您就可以配置不同的地图,如Jimmy Bogard的this answer所示,希望以不同的方式映射单个类型。

答案 2 :(得分: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建议的不同配置文件,您可以使用它来暂时取回控制权。我亲自尝试过。