是否可以“说服”自动映射器暂时暂停特定映射

本文关键字:映射 暂停 说服 是否 | 更新日期: 2023-09-27 18:34:54

可以"说服"自动映射器暂时暂停特定映射吗?

为了说明我试图完成的任务,我将使用一个插图。假设我有一个存储库,StudentRepository,它使用 LINQ 与数据库对象(表(进行交互,如学生、课程、活动、俱乐部等。在应用程序端,有匹配的域对象学生、课程、活动、俱乐部。学生类包含类型为"课程"、"活动和俱乐部"的数组成员,如下所示:

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
    }
}

是否有可能"说服"自动映射器暂停一个功能块中的映射?例如:

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 个学生的俱乐部。

是否有可能"说服"自动映射器暂停一个功能块中的映射?

据我所知,最好的方法 - 像这样使用 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
            });
    }
}

实现此目的的一种方法是为每个场景创建单独的映射引擎实例,这样您就可以配置不同的映射,正如 Jimmy Bogard 关于希望以不同方式映射单个类型的回答中所建议的那样。

嗯...谢谢大家的反馈。我花时间考虑了所有的答案和建议。没有一个特别好地呈现,尽管它们提供了很多值得思考的东西。我想我应该注射我尝试过的东西。(免责声明:我的观点是,这是一种肮脏的方法——很多事情都可能出错——墨菲定律仍然适用(。您可以利用特定实例中的忽略功能来"挂起"映射。通常,在尝试和捕获块中,如下所示:

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建议的那样,您可以使用它暂时恢复控制权。我亲自尝试过。