get; set; }
public string Category => CategoryCode == 1001 ? ".NET" : "杂谈";
public string ReleaseDate { get; set; }
public short CommentCounts { get; set; }
public virtual int Count { get; set; }
}
首先我们需要创建一个实体映射的配置类,需要继承于 AutoMapper 的 Profile 类,在无参构造函数中,我们就可以通过 CreateMap 方法去创建两个实体间的映射关系。
public class PostProfile : Profile
{
/// <summary>
/// ctor
/// </summary>
public PostProfile()
{
// 配置 mapping 规则
//
CreateMap<PostModel, PostViewModel>();
}
}
通过泛型的 CreateMap 方法就可以完成我们从 PostModel(PO) 到 PostViewModel(VO) 的实体映射。当然,因为 AutoMapper 默认是通过匹配字段名称和类型进行自动匹配,所以如果你进行转换的两个类的中的某些字段名称不一样,这里我们就需要进行手动的编写转换规则。
就像在这个需要进行实体映射的示例代码中,PostViewModel 中的 CommentCounts 字段是根据 PostModel 中 CommentModel 集合的数据个数进行赋值的,所以这里我们就需要对这个字段的转换规则进行修改。
在 AutoMapper 中,我们可以通过 ForMember 方法对映射规则做进一步的加工。这里我们需要指明 PostViewModel 的 CommentCounts 字段的值是通过对 PostModel 中的 Comments 信息进行求和从而获取到的,最终实现的转换代码如下所示。
public class PostProfile : Profile
{
/// <summary>
/// ctor
/// </summary>
public PostProfile()
{
// 配置 mapping 规则
//
CreateMap<PostModel, PostViewModel>()
.ForMember(destination => destination.CommentCounts, source => source.MapFrom(i => i.Comments.Count()));
}
}
ForMember 方法不仅可以进行指定不同名称的字段进行转换,也可以通过编写规则实现字段类型的转换。例如这里 PO 中的 ReleaseDate 字段其实是 DateTime 类型的,我们需要通过编写规则将该字段对应到 VO 中 string 类型的 ReleaseDate 字段上,最终的实现代码如下所示。
public class PostProfile : Profile
{
/// <summary>
/// ctor
/// </summary>
public PostProfile()
{
// Config mapping rules
//
CreateMap<PostModel, PostViewModel>()
.ForMember(destination => destination.CommentCounts, source => source.MapFrom(i => i.Comments.Count()))
.ForMember(destination => destination.ReleaseDate, source => source.ConvertUsing(new DateTimeConverter()));
}
}
public class DateTimeConverter : IValueConverter<DateTime, string>
{
public string Convert(DateTime source, ResolutionContext context)
=> source.ToString("yyyy-MM-dd HH:mm:ss");
}
这里很多人可能习惯将所有的实体映射规则都放到同一个 Profile 文件里面,因为这里采用是单体架构的项目,所以整个项目中会存在不同的模块,所以这里我是按照每个模块去创建对应的 Profile 文件。实际在 ingos-server 这个项目中的使用方式见下图所示。
当我们创建好对应的映射规则后,因为我们是采用依赖注入的方式进行使用,所以这里我们就需要将我们的匹配规则注入到 IServiceCollection 中。从之前加载的程序集的 github readme 描述中可以看到,我们需要将配置好的 Profile 类通过 AddAutoMapper 这个扩展方法进行注入。
因为我们在实际项目中可能存在多个自定义的 Profile 文件,而我们肯定是需要将这些自定义规则都注入到 IServiceCollection 中。所以我在 AddAutoMapper 这个方法的基础上创建了一个 AddAutoMapperProfiles 方法去注入我们的实体映射规则。
通过 AutoMapper 的说明我们可以看出来,所有的自定义的 Profile 类都是需要继承于 AutoMapper 的 Profile 基类,所以这里我是采用反射的方式,通过获取到程序集中所有继承于 Profile 类的类文件进行批量的注入到 IServiceCollection 中,具体的实现代码如下所示。
/// <summary>
/// Automapper 映射规则配置扩展方法
/// </summary>
public static class AutoMapperExtension
{
public static IServiceCollection AddAutoMapperProfiles(this IServiceCollection services)
{
// 从 appsettings.json 中获取包含配置规则的程序集信息
string assemblies = ConfigurationManager.GetConfig("Assembly:Mapper");
if (!string.IsNullOrEmpty(assemblies))
{
var profiles = new List<Type>();
// 获取继承的 Profile 类型信息
var parentType = typeof(Profile);
foreach (var item in assemblies.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries))
{
// 获