Auto Mapper使用历程

Auto Mapper使用历程

问题记录时间:2020-04-03

1.数据模型直接给DTO模型赋值

在公司的新项目中,我们应用了一定的规范引入了DTO模型,在开始的时候我们直接使用的数据模型给DTO模型赋值。

//这个就是我们以前模型的例子
private EmailAcceptModel GetModel(E_MailMessage_Accept model)
{
    if (model == null)
        return null;
    return new EmailAcceptModel
    {
        Id = model.id,
        Status = model.status,
        Body = model.body,
        BodyEncoding = model.body_encoding,
        CreateDate = model.create_date,
        CreateMan = model.create_man,
        FromAddress = model.from_Address,
        FromDisplayName = model.from_DisplayName,
        FromHost = model.from_Host,
        FromUser = model.from_User,
        //MainId = model.main_id,
        ModifyDate = model.Modify_date,
        ModifyMan = model.Modify_man,
        Subject = model.subject,
        SubjectEncoding = model.subject_encoding,
        Times = model.times,
        ToId = model.to_id,
        Uid = model.uid,
        OrderId = model.OrderID,
        DealMan = model.deal_man
    };
}

2.使用Auto Mapper给DTO模型赋值

但是这里会出现一个问题:每当我们在数据库中更改一个字段并且需要让他加载到前端的时候,我们就必须修改数据模型,DTO模型,以及所有出现一下代码中赋值的所有地方,前面两个修改还是比较简单,但是模型转换赋值的地方在程序中会出现多次,修改起来非常麻烦。所以我们找到了AutoMapper组件。并写了一下扩展方法。

public static class AutoMapExt
{
    /// <summary>
    ///  类型映射,默认字段名字一一对应
    /// </summary>
    /// <typeparam name="TDestination">转化之后的model,可以理解为viewmodel</typeparam>
    /// <typeparam name="TSource">要被转化的实体,Entity</typeparam>
    /// <param name="source">可以使用这个扩展方法的类型,任何引用类型</param>
    /// <returns>转化之后的实体</returns>
    public static TDestination MapTo<TSource, TDestination>(this TSource source)
        where TDestination : class
            where TSource : class
            {
                if (source == null) return default(TDestination);
                var config = new MapperConfiguration(cfg => cfg.CreateMap<TSource, TDestination>());
                var mapper = config.CreateMapper();
                return mapper.Map<TDestination>(source);
            }
}

一开是我们用的很开心,直接把代码生成器中的原来直接生成模型转换的代码替换成了这个方法:

model.MapTo<CommLogModel, Comm_Log>();//程序里面开始大面积应用这种代码
list.Select(a=>a.MapTo<CommLogModel, Comm_Log>());//这种返回列表页面数据

大家看到以上代码估计就知道我们这种方式的问题出现在哪里。在一个需要返回1000+数据的页面中,我们直接使用了以上方法,然后直接掉到坑里了,返回数据耗时大概在60000ms左右。

3.解决列表转换中使用Auto Mapper的性能问题

然后就找到了在 MapTo()方法中所有的转换都会创建一次MapperConfiguration在成千上万次的创建中,这个方法的效率直线下降。于是我们重新创建了这个方法。

/// <summary>
///  类型映射,默认字段名字一一对应,用于直接映射列表
/// </summary>
/// <typeparam name="TDestination">转化之后的model,可以理解为viewmodel</typeparam>
/// <typeparam name="TSource">要被转化的实体,Entity</typeparam>
/// <param name="source">可以使用这个扩展方法的类型,任何引用类型</param>
/// <returns>转化之后的实体</returns>
public static List<TDestination> MapListTo<TSource, TDestination>(this List<TSource> source)
    where TDestination : class
    where TSource : class
{
        var type = typeof(TSource);

        if (source == null) return null;
        var config = new MapperConfiguration(cfg => cfg.CreateMap<TSource, TDestination>());
        var mapper = config.CreateMapper();
        return mapper.Map<List<TSource>, List<TDestination>>(source);
}

4.ABP中Auto Mapper的应用及后续优化的方向

这个问题让我想到了在ABP中看到的Auto Mapper组件的应用,在ABP中,把MapperConfiguration注册为单例模式,在项目开始的时候加载一次 ,然后配置模型的映射关系使用。这样可以节省大量的创建开销。后续项目我们也可以使用这种方式改造。提升效率。

posted @ 2020-04-03 10:21  lwq202  阅读(577)  评论(0编辑  收藏  举报