Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can AutoMapper be "persuaded" to temporarily suspend particular mappings?

Can AutoMapper be "persuaded" to temporarily suspend particular mappings?

To illustrate what am trying to accomplish, I will use an illustration. Suppose that I have a repository, StudentRepository, that uses LINQ to interacts with database objects (tables) like Students, Courses, Activities, Clubs etc. On the application side, there are matching domain objects Student, Course, Activity, Club. The Student class contains array members of type Course, Activity, and Club like:

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

AutoMapper is configured to map the database objects to the domain objects where the mappings are defined in a static constructor of StudentRepository like:

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

    }
}

Is it possible to "persuade" AutoMapper to suspend the mappings within one function block? For example:

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
}

NOTE "for some specific reasons": One reason one may want to take control away from AutoMapper would be this http://codebetter.com/davidhayden/2007/08/06/linq-to-sql-query-tuning-appears-to-break-down-in-more-advanced-scenarios/ where in the case of a 1:n associations, LINQ to SQL only supports joining-in one 1:n association per query. AutoMapper would be inefficient here - making N calls to load Courses for N students returned, N more calls to load Activities for the same N students returned, and possibly N more calls to load Clubs for the same N students returned.

like image 335
John Gathogo Avatar asked May 22 '12 14:05

John Gathogo


People also ask

When should you not use AutoMapper?

If you have to do complex mapping behavior, it might be better to avoid using AutoMapper for that scenario. Reverse mapping can get very complicated very quickly, and unless it's very simple, you can have business logic showing up in mapping configuration.

Does AutoMapper map both ways?

Yes, or you can call CreateMap<ModelClass, ViewModelClass>(). ReverseMap() .

Why do we use AutoMapper?

AutoMapper is used whenever there are many data properties for objects, and we need to map them between the object of source class to the object of destination class, Along with the knowledge of data structure and algorithms, a developer is required to have excellent development skills as well.

How do I use AutoMapper to list a map?

How do I use AutoMapper? First, you need both a source and destination type to work with. The destination type's design can be influenced by the layer in which it lives, but AutoMapper works best as long as the names of the members match up to the source type's members.


1 Answers

Is it possible to "persuade" AutoMapper to suspend the mappings within one function block?

As I know, the best way to do it - use Ignore() like this

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

    }
}

Also, as it was noticed before, I'd recommend you to use different profiles for each goal you want to achieve.Here is a example

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
            });
    }
}
like image 85
Andriy Zakharko Avatar answered Sep 24 '22 00:09

Andriy Zakharko