在多层结构中,经常用到对象到对象的转化,比如数据库Entity到Model的转化,Model和ViewModel的转换,手工去写复制太过麻烦。AutoMapper就是一个可以实现自动转换的类库。
AutoMapper是一个对象与对象的映射器。对象-对象映射通过将一种类型的输入对象转换为不同类型的输出对象来工作。让AutoMapper感兴趣的是,它提供了一些有趣的约定,从而弄清楚如何将类型A映射到类型B.只要类型B遵循AutoMapper建立的约定,映射两种类型几乎就是零配置。
使用Nuget 直接引用AutoMapper就可以使用AutoMapper了。
AutoMapper.Mapper.Initialize(m => {m.CreateMap<Model,ViewModel>();});
var vModel = AutoMapper.Mapper.Map<ViewModel>(modelObj);
var model = AUtoMapper.Mapper.Map<Model>(vModel);
public class Book
{
public string Title { get; set; }
public string Note { get; set; }
}
public class BookViewModel
{
public string Title { get; set; }
public string Desc { get; set; }
}
AutoMapper.Mapper.Initialize(m => {
m.CreateMap<Book, BookViewModel>().ForMember(c => c.Note, q =>
{
q.MapFrom(z => z.Des);
});
});
但是上述代码只可以实现DTO,没办法实现OTD
var vBook = Mapper.Map<BookViewModel>(book); //正确
var book = Mapper.Map<BookViewModel>(vBook); //报错
如果要实现反转,需要如下改变:增加.ReverseMap()
AutoMapper.Mapper.Initialize(m => {
m.CreateMap<Book, BookViewModel>().ForMember(c => c.Note, q =>
{
q.MapFrom(z => z.Des);
}).ReverseMap();
});
完全可以自动实现转化Author.Name 和AuthorName的关系
public class Author
{
public string Name { get; set; }
}
public class Book
{
public string Title { get; set; }
public Author AuthorName { get; set; }
public string Note { get; set; }
}
public class BookViewModel
{
public string Title { get; set; }
public string Author{ get; set; }
public string Desc { get; set; }
}
public class Author
{
public string Name { get; set; }
}
public class Book
{
public string Title { get; set; }
public Author Author { get; set; }
public string Note { get; set; }
}
public class BookViewModel
{
public string Title { get; set; }
public string Author{ get; set; }
public string Desc { get; set; }
}
上面的代码中Author在两处的类型不一样,但是名字并不是按照约定的。那么这样要如何实现呢。
.ForMember(c => c.Author, q =>
{
q.MapFrom(z => z.Author.Name);
})
反转的部分和上一步的差不多,总体代码如下。
m.CreateMap<Book, BookViewModel>()
.ForMember(c => c.Author, q =>
{
q.MapFrom(z => z.Author.Name);
})
.ForMember(c => c.Desc, q =>
{
q.MapFrom(z => z.Note);
}).ReverseMap();
但是我们发现反转没成功,需要规定如何反转,修改如下
AutoMapper.Mapper.Initialize(m =>
{
m.CreateMap<Book, BookViewModel>()
.ForMember(c => c.Author, q =>
{
q.MapFrom(z => z.Author.Name);
})
.ForMember(c => c.Desc, q =>
{
q.MapFrom(z => z.Note);
}).ReverseMap().ForPath(r => r.Author.Name, q => q.MapFrom(z => z.Author));
});
public class Source
{
public string Value1 { get; set; }
public string Value2 { get; set; }
public string Value3 { get; set; }
}
public class Source
{
public string Value1 { get; set; }
public string Value2 { get; set; }
public string Value3 { get; set; }
}
public void Example()
{
Mapper.Initialize(cfg => {
cfg.CreateMap<string, int>().ConvertUsing(s => Convert.ToInt32(s));
cfg.CreateMap<string, DateTime>().ConvertUsing(new DateTimeTypeConverter());
cfg.CreateMap<string, Type>().ConvertUsing<TypeTypeConverter>();
cfg.CreateMap<Source, Destination>();
});
Mapper.AssertConfigurationIsValid();
var source = new Source
{
Value1 = "5",
Value2 = "01/01/2000",
Value3 = "AutoMapperSamples.GlobalTypeConverters.GlobalTypeConverters+Destination"
};
Destination result = Mapper.Map<Source, Destination>(source);
result.Value3.ShouldEqual(typeof(Destination));
}
public class DateTimeTypeConverter : ITypeConverter<string, DateTime>
{
public DateTime Convert(string source, DateTime destination, ResolutionContext context)
{
return System.Convert.ToDateTime(source);
}
}
public class TypeTypeConverter : ITypeConverter<string, Type>
{
public Type Convert(string source, Type destination, ResolutionContext context)
{
return Assembly.GetExecutingAssembly().GetType(source);
}
}
只需要继承这个接口
public interface ITypeConverter<in TSource, TDestination>
{
TDestination Convert(TSource source, TDestination destination, ResolutionContext context);
}
大多数的时候,我们只需要在用到对象的时候使用var obj = Mapper.Map(source)来实现即可,注册和配置可以集中化的管理,或者使用依赖注入。
我只能简单的讲解下我的理解。还有很多部分,需要你来亲自体验:
下面有非常不错的,原文翻译,可以挨着敲敲代码
http://blog.csdn.net/wulex/article/category/6408862