AutoMapper使用笔记

来源:互联网 发布:淘宝网商家中心 编辑:程序博客网 时间:2024/05/16 12:01

AutoMapper是一个.NET的对象映射工具。

项目地址:https://github.com/AutoMapper/AutoMapper。

帮助文档:https://github.com/AutoMapper/AutoMapper/wiki

主要用途

领域对象与DTO之间的转换、数据库查询结果映射至实体对象。

使用笔记

场景1:源类型BlogEntry,目标类型BlogPostDto,指定属性进行映射(BlogEntry.ID对应于BlogPostDto.PostId)。

代码:

AutoMapper.Mapper.CreateMap<BlogEntry, BlogPostDto>()                .ForMember(dto => dto.PostId, opt => opt.MapFrom(entity => entity.ID));


场景2:IDataReader映射至实体类

代码:

复制代码
using (IDataReader reader = _db.ExecuteReader(command)){    if (reader.Read())    {        return AutoMapper.Mapper.DynamicMap<BlogConfig>(reader);    }}
复制代码

场景3:列表类型之间的映射,比如:源类型List<BlogSite>,目标类型List<BlogSiteDto>

代码如下:

AutoMapper.Mapper.CreateMap<BlogSite, BlogSiteDto>();var blogSiteDto = AutoMapper.Mapper.Map<List<BlogSite>, List<BlogSiteDto>>(blogSite);

注:必须要先通过CreateMap建立BlogSite与BlogSiteDto的映射关系。

场景4:在映射时为目标实例的属性指定值

代码如下:

var blogSiteDto = new BlogSiteDto();AutoMapper.Mapper.CreateMap<BlogEntry, BlogPostDto>()                .ForMember(dto => dto.BlogSiteDto, opt => opt.UseValue(blogSiteDto));

注:BlogSiteDto是BlogPostDto的一个属性。

补充:

AutoMapper的配置(比如AutoMapper.Mapper.CreateMap<BlogSite, BlogSiteDto>();)建议放在程序启动时,比如Global.asax的Application_Start, BootStrapper。

 

 

 

上篇随笔写的是我们在新版博客后台开发中用上了新式武器——Entity Framework,该武器火力猛,威力大,但使用中发现在某些场景下显得不够灵活,后来不得不引进轻量级常规武器——AutoMapper。

我们遇到的场景是一个复杂的实体类,有很多属性,数据库操作是一个跨数据库查询,查询的字段远远少于实体类的属性。

对于跨数据库查询,我们没有找到通过LINQ to Entities实现的方法,于是就用DbSet.SqlQuery调用存储过程进行查询,代码如下:

using (BlogDbContext context = new BlogDbContext()){ string sql = string.Format("EXEC [blog_Entry_Get] @BlogID={0},@EntryID={1}", blogId, entryId); BlogEntry entry = context.BlogEntries.SqlQuery(sql).Single();}

虽然不能使用LINQ进行查询,但我们不想在这里抛弃这个新式武器,不能发射导弹,可以用一下机关枪嘛。于是,如上面的代码所示,用SqlQuery进行查询,用Entity Framework完成查询结果与实体类的数据映射。

结果发现,Entity Framework是依赖于实体类的属性进行映射的。如果把Entity Framework比作机关枪,那实体类的属性就是子弹,每颗子弹只能攻击唯一对应的目标,在射击过程中,只要有一颗子弹攻击的目标不存在,机枪就会卡壳(子弹决定目标?)。也就是Entity Framework会在IDataReader中查找每个实体类属性对应的值,而我们的应用场景却是“查询的字段远远少于实体类的属性”,这时,Entity Framework成为了一堆废铁(这个说法不妥,可以通过modelBuilder.Entity<BlogEntry>().Ignor忽略不需要映射的字段,但是,如果不同的查询返回的字段不同,这个方法就不管用了)。

为什么不由目标决定子弹?出现什么目标,用什么子弹,既节省子弹,又不会卡壳。也就是根据查询结果给对应的实体类属性赋值。难道这个新式武器也有设计缺陷,没有考虑到这样的应用场景?还是我们不会使用?

翻来覆去地摆弄它,还是没搞定,只能换武器...

数据库查询换成了旧式武器Enterprise Library,并引进了新的轻量级常规武器AutoMapper进行查询结果与实体类的映射(而且是开源的)。

“轻量级”果然名不虚转,简单易用,针对性强,我们用它轻松解决了问题,代码如下:

复制代码
SqlCommand command = (SqlCommand)_sqldb.GetStoredProcCommand("[blog_Entry_Get]");command.Parameters.AddWithValue("@BlogID", blogId);command.Parameters.AddWithValue("@EntryID", entryId);using (IDataReader reader = _sqldb.ExecuteReader(command)){ if (reader.Read()) { BlogEntry entry = AutoMapper.Mapper.DynamicMap<BlogEntry>(reader); }}
复制代码

今天试用了,以后试用emitmapper

但感觉缺少一个功能entity to SqlParamentCollement  

 

 

 //todo:可考虑使用下面的方法替换上面相关类
        public static TResult ExecuteScalar2<TResult, TEntity>(Database DB, DbCommand dbCommand, TEntity entity) where TEntity : class
        {
            DbParameter[] dbParameterArr = GetDbParameters<TEntity>(entity);
            dbCommand.Parameters.AddRange(dbParameterArr);
            object result = DB.ExecuteScalar(dbCommand);
            if (result == DBNull.Value)
                return default(TResult);
            return (TResult)Convert.ChangeType(result, typeof(TResult));
        }
        public static List<T> ConvertToList2<T>(IDataReader dr) where T : class, new()
        {
            List<T> list = null;
            var properties = GetProperties<T>();
            var columnNames = GetColumnNames(dr);
            while (dr.Read())
            {
                if (list == null)
                {
                    list = new List<T>();
                }
                T o = new T();
                foreach (var p in properties)
                {
                    var columnName = p.Name;
                    if (columnNames.Contains(columnName))
                    {
                        if (!Convert.IsDBNull(dr[columnName]))
                        {
                            object value = dr[columnName];
                            if (value.GetType() != p.PropertyType)
                            {
                                value = Convert.ChangeType(value, p.PropertyType);
                            }
                            p.SetValue(o, value, null);
                        }
                    }
                }
                list.Add(o);
            }
            return list;
        }
        public static T ConvertToEntity2<T>(IDataReader dr) where T : class,new()
        {
            T o = new T();
            PropertyInfo[] properties = GetProperties<T>();
            var columnNames = GetColumnNames(dr);

            foreach (var p in properties)
            {
                var columnName = p.Name;
                if (columnNames.Contains(columnName))
                {
                    if (!Convert.IsDBNull(dr[columnName]))
                    {
                        object value = dr[columnName];
                        if (value.GetType() != p.PropertyType)
                        {
                            value = Convert.ChangeType(value, p.PropertyType);
                        }
                        p.SetValue(o, value, null);
                    }
                }
            }
            return o;
        }

        private static PropertyInfo[] GetProperties<T>() where T : class
        {
            Type t = typeof(T);
            string key = string.Format("DbHelper_GetProperties_{0}", t.FullName);
            MemoryCache cache = MemoryCache.Default;
            if (cache[key] == null)
            {
                PropertyInfo[] properties = t.GetProperties();
                cache.Add(key, properties, MemoryCache.InfiniteAbsoluteExpiration);
                return properties;
            }
            return cache[key] as PropertyInfo[];
        }
        private static DbParameter[] GetDbParameters<T>(T entity) where T : class
        {
            IList<DbParameter> parameterList = new List<DbParameter>();
            PropertyInfo[] properties = GetProperties<T>();
            foreach (var p in properties)
            {
                SqlParameter sqlParameter = new SqlParameter();
                sqlParameter.ParameterName = string.Format("@{0}", p.Name);
                sqlParameter.Value = p.GetValue(entity, null);
                sqlParameter.DbType = GetDbType(p.PropertyType);
                parameterList.Add(sqlParameter);
            }
            return parameterList.ToArray();
        }
        private static List<string> GetColumnNames(IDataReader dr)
        {
            List<string> list = new List<string>();
            for (int i = 0; i < dr.FieldCount; i++)
            {
                var fileName = dr.GetName(i);
                list.Add(fileName);
            }
            return list;
        }
        private static DbType GetDbType(Type t)
        {
            string typeName = t.Name.ToLower();
            DbType dbType;
            switch (typeName)
            {
                case "guid":
                    dbType = DbType.Guid;
                    break;
                case "short":
                    dbType = DbType.Int16;
                    break;
                case "byte":
                    dbType = DbType.Byte;
                    break;
                case "int":
                    dbType = DbType.Int32;
                    break;
                case "long":
                    dbType = DbType.Int64;
                    break;
                case "dateTime":
                    dbType = DbType.DateTime;
                    break;
                case "double":
                    dbType = DbType.Double;
                    break;
                case "decimal":
                    dbType = DbType.Decimal;
                    break;
                case "float":
                    dbType = DbType.Decimal;
                    break;
                case "bool":
                    dbType = DbType.Boolean;
                    break;
                default:
                    dbType = DbType.String;
                    break;
            }
            return dbType;
        }

 

原创粉丝点击