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.
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.
Yes, or you can call CreateMap<ModelClass, ViewModelClass>(). ReverseMap() .
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? 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.
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
});
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With