نگاشت اشیاء در AutoMapper توسط Attribute ها #2 - تبدیل ویژگیها به نگاشت
نویسنده: مرتضی رییسی
تاریخ: ۱۳۹۴/۰۸/۲۵ ۱۳:۴۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
public static void Initialize(Assembly assembly)
{
//register global convertors.
AutoMapper.Mapper.CreateMap<DateTime, string>().ConvertUsing<DateTimeToPersianDateTimeConverter>();
var typesToMap = from t in assembly.GetTypes()
let attr = t.GetCustomAttribute<MapFromAttribute>()
where attr != null
select new {SourceType = attr.SourceType, Destination = t, Attribute = attr};
foreach (var map in typesToMap)
{
AutoMapper.Mapper.CreateMap(map.SourceType, map.Destination)
.DoMapForMemberAttribute() // for different property names in source and destination
.DoIgnoreMapAttribute()// ignore specified properties
.DoUseValueResolverAttribute()// set value resolvers
.DoIgnoreAllNonExisting()// its have to be the latest.
;
} //endeach
AutoMapper.Mapper.AssertConfigurationIsValid();
} public static IMappingExpression DoMapForMemberAttribute(this IMappingExpression expression)
{
var ok =
from p in expression.TypeMap.DestinationType.GetProperties()
let attr = p.GetCustomAttribute<MapForMemberAttribute>()
where attr != null
select new {AttributeValue = attr, PropertyName = p.Name};
foreach (var property in ok)
{
expression.ForMember(property.PropertyName,
opt => opt.MapFrom(property.AttributeValue.MemberToMap));
}
return expression;
} public static IMappingExpression DoIgnoreAttribute(this IMappingExpression expression)
{
foreach (var property in
expression.TypeMap.DestinationType.GetProperties()
.Where(x => x.GetCustomAttribute<IgnoreMapAttribute>() != null))
{
expression.ForMember(property.Name, opt => opt.Ignore());
}
return expression;
} public static IMappingExpression DoUseValueResolverAttribute(this IMappingExpression expression)
{
var ok =
from p in expression.TypeMap.DestinationType.GetProperties()
let attr = p.GetCustomAttribute<UseValueResolverAttribute>()
where attr != null
select new {AttributeValue = attr, PropertyName = p.Name};
foreach (var property in ok)
{
expression.ForMember(property.PropertyName,
opt => opt.ResolveUsing(property.AttributeValue.ValueResolver));
}
return expression;
} public static IMappingExpression DoIgnoreAllNonExisting(this IMappingExpression expression)
{
var attr = expression.TypeMap.DestinationType.GetCustomAttribute<MapFromAttribute>();
if (attr?.IgnoreAllNonExistingProperty == false)//instead of if(attr == null || attr.IgnoreAllNonExistingProperty == false)
return expression;
foreach (var property in expression.TypeMap.GetUnmappedPropertyNames())
{
expression.ForMember(property, opt => opt.Ignore());
}
return expression;
} public class Student
{
public virtual int Id { set; get; }
public virtual string Name { set; get; }
public virtual string Family { set; get; }
public virtual string Email { set; get; }
public virtual DateTime RegisterDateTime { set; get; }
public virtual ICollection<Book> Books { set; get; }
}
public class Book
{
public virtual int Id { set; get; }
public virtual string Name { set; get; }
public virtual DateTime BorrowDateTime { set; get; }
public virtual DateTime ExpiredDateTime { set; get; }
public virtual decimal Price { set; get; }
[ForeignKey("StudentIdFk")]
public virtual Student Student { set; get; }
public virtual int StudentIdFk { set; get; }
} [MapFrom(typeof (Student), ignoreAllNonExistingProperty: true, alsoCopyMetadata: true)]
public class AdminStudentViewModel
{
// [IgnoreMap]
public int Id { set; get; }
[MapForMember("Name")]
public string FirstName { set; get; }
[MapForMember("Family")]
public string LastName { set; get; }
[IgnoreMap]
public string Email { set; get; }
[MapForMember("RegisterDateTime")]
public string RegisterDateTimePersian { set; get; }
[UseValueResolver(typeof (BookCountValueResolver))]
public int BookCounts { set; get; }
[UseValueResolver(typeof (BookPriceValueResolver))]
public decimal TotalBookPrice { set; get; }
}; public class BookCountValueResolver : ValueResolver<Student, int>
{
protected override int ResolveCore(Student source) => source.Books.Count;
};
public class BookPriceValueResolver : ValueResolver<Student, decimal>
{
protected override decimal ResolveCore(Student source) => source.Books.Sum(b => b.Price);
}; static void Main(string[] args)
{
var assemblyToLoad = Assembly.GetAssembly(typeof (AdminStudentViewModel));//get assembly
global::AttributesForAutomapper.Configuration.Initialize(assemblyToLoad);//init automaper
IList<Student> lst;
using (var context = new MySampleContext())
{
lst = context.Students.Include(x => x.Books).ToList();
}
foreach (var student in lst)
{
WriteLine( $"[{student.Id}]*\n{student.Name} {student.Family}.\nmailto:{student.Email}.\nRegistered at'{student.RegisterDateTime}'");
foreach (var book in student.Books)
WriteLine($"\tBook name:{book.Name}, Book price:{book.Price}");
}
var lstViewModel = AutoMapper.Mapper.Map<IList<Student>, IList<AdminStudentViewModel>>(lst);
foreach (var adminStudentViewModel in lstViewModel)
{
WriteLine(
$"[{adminStudentViewModel.Id}]*\n\t{adminStudentViewModel.FirstName} {adminStudentViewModel.LastName}.\n\t" +
$"mailto:{adminStudentViewModel.Email}.\n\tRegistered at'{adminStudentViewModel.RegisterDateTimePersian}'\n\t" +
$"Book Counts: {adminStudentViewModel.BookCounts} with total price of {adminStudentViewModel.TotalBookPrice}");
}
WriteLine("Press any key to exit...");
ReadKey();
} [1]*
Morteza Raeisi.
mailto:MrRaeisi@outlook.com.
Registered at'23/08/1392 19:11:43' // I'm using Windows 10 with Persian calendar as default, On other OS or calendar settings, this value is different.
Book name:AutoMapper Attr, Book price:1000.00
Book name:Second Book, Book price:2500.00
Book name:Hungry Book, Book price:2500.00
...
[1]*
Morteza Raeisi. //MapForMemebers
mailto:. // IgnoreMap
Registered at'1392/08/23 19:11' // Convert using
Book Counts: 3 with total price of 6000.00 // Value resolvers
...