zoukankan      html  css  js  c++  java
  • Dapper数据库字段和model属性映射

    背景:

    在.net core 2.0 Asp.mvc 项目中使用dapper 框架

    一、

    数据库字段名和model属性名一一对应时,直接只用dapper方法是没有问题的,比如:

    //实体类
    public class Books
        {
            [Dapper.Key]
            public int Id { get; set; }
    
            public string Name { get; set; }
    
            public string Author { get; set; }
    }
    

    数据库:book表

    直接使用dapper对象的方法,传入model对象:

    //默认映射
    string sql = $"SELECT * FROM book ";
    database.QueryListSQL<ReadBooks>(sql).ToList();
    
    //直接传入实体对象
    bool result = await database.CreateAsync(book) > 0;

    好处是不需要在sql语句中将字段一个个写出来,直接使用table-model映射关系,非常便利!

    二、

    但是,也会有字段名和属性名不对应的情况,比如:

    public class ReadBooks
    {      
    
        public DateTime CreateTime { get; set; }
    }

    那么,在C#程序中,使用Dapper做查询时,如何配置数据表字段(列)和实体类属性之间的映射呢?

    method 1:

    查询时,可以在select语句中使用AS别名,别名与model对应:

    var sql = @"select create_time AS CreateTime from book";
    
    database.Single<Books>(sql);

    插入/更新时,依然需要 列名-值 :

    //dapper插入语句,表名和字段名
    database.InsertSQL($@"book",new DataColumn("Author", book.Author),
                                new DataColumn("Name", book.Name),
                                new DataColumn("create_time", DateTime.Now)
                      );

     

    method 2:

    查询时,还可以使用Linq:

    //搭配动态类型dynamic使用
     
    List<Books> book= database.Query<dynamic>(sql)
                                      .Select(item => new Books()
                                      {
                                          CreatTime= creat_time
                                      }
                                      .ToList();

    method 3:

    如果有很多数据库表字段和model属性不对应的话,我们每次都使用别名和linq就有些麻烦,如果能像EF那样,在model属性上加一个Attribute来表明字段和属性映射关系就好了,EF:

    class School
    {
        /*
          若属性名和数据库字段不一致(不区分大小写)则查询不出数据,如果使用EF则可以通过Column特性
          建立属性和数据表字段之间的映射关系,Dapper则不行
        */
        //[Column("Name")]
        public string Title { set; get; }
        public string Address { set; get; }
    }

    Dapper虽然有colmun的特性,但是并不能完成字段-属性映射;

    我们需要手动拓展一个colmun特性出来,以完成如EF的绑定。

    1,添加一个类ColumnAttributeTypeMapper,用于字段-属性映射:

    using Dapper;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    
    namespace 命名空间
    {
       
            /// <summary>
            /// Uses the Name value of the <see cref="ColumnAttribute"/> specified to determine
            /// the association between the name of the column in the query results and the member to
            /// which it will be extracted. If no column mapping is present all members are mapped as
            /// usual.
            /// </summary>
            /// <typeparam name="T">The type of the object that this association between the mapper applies to.</typeparam>
            public class ColumnAttributeTypeMapper<T> : FallbackTypeMapper
            {
                public ColumnAttributeTypeMapper()
                    : base(new SqlMapper.ITypeMap[]
                        {
                        new CustomPropertyTypeMap(
                           typeof(T),
                           (type, columnName) =>
                               type.GetProperties().FirstOrDefault(prop =>
                                   prop.GetCustomAttributes(false)
                                       .OfType<ColumnAttribute>()
                                       .Any(attr => attr.Name == columnName)
                                   )
                           ),
                        new DefaultTypeMap(typeof(T))
                        })
                {
                }
            }
    
            [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
            public class ColumnAttribute : Attribute
            {
                public string Name { get; set; }
            }
    
            public class FallbackTypeMapper : SqlMapper.ITypeMap
            {
                private readonly IEnumerable<SqlMapper.ITypeMap> _mappers;
    
                public FallbackTypeMapper(IEnumerable<SqlMapper.ITypeMap> mappers)
                {
                    _mappers = mappers;
                }
    
    
                public ConstructorInfo FindConstructor(string[] names, Type[] types)
                {
                    foreach (var mapper in _mappers)
                    {
                        try
                        {
                            ConstructorInfo result = mapper.FindConstructor(names, types);
                            if (result != null)
                            {
                                return result;
                            }
                        }
                        catch (NotImplementedException)
                        {
                        }
                    }
                    return null;
                }
    
                public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)
                {
                    foreach (var mapper in _mappers)
                    {
                        try
                        {
                            var result = mapper.GetConstructorParameter(constructor, columnName);
                            if (result != null)
                            {
                                return result;
                            }
                        }
                        catch (NotImplementedException)
                        {
                        }
                    }
                    return null;
                }
    
                public SqlMapper.IMemberMap GetMember(string columnName)
                {
                    foreach (var mapper in _mappers)
                    {
                        try
                        {
                            var result = mapper.GetMember(columnName);
                            if (result != null)
                            {
                                return result;
                            }
                        }
                        catch (NotImplementedException)
                        {
                        }
                    }
                    return null;
                }
    
    
                public ConstructorInfo FindExplicitConstructor()
                {
                    return _mappers
                        .Select(mapper => mapper.FindExplicitConstructor())
                        .FirstOrDefault(result => result != null);
                }
            }
    
        
    }
    

    2,再添加一个类ColumnMapper,用于添加映射关系:

    using Dapper;
    using 引入需要的.Models;
    
    namespace 项目命名空间
    {
        public class ColumnMapper
        {
            public static void SetMapper()
            {
                //数据库字段名和c#属性名不一致,手动添加映射关系
                SqlMapper.SetTypeMap(typeof(Books), new  ColumnAttributeTypeMapper<Books>());
                
                //每个需要用到[colmun(Name="")]特性的model,都要在这里添加映射
            }
        }
    }
    

    3,在starup.cs类的中方法注册:

    public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc();
                services.AddSession();
                
                //调用前面的静态方法,将映射关系注册
                ColumnMapper.SetMapper();
    }

    4,最后就可以在model的属性名上添加特性来映射到数据库字段名了:

    using 引入新加的类.Helper;
    
    public class Books
    {
            [Column(Name = "create_time")]
            public DateTime CreateTime { get; set; }
    }

    这样我们就可以在所有的不与数据库对应的model中,方便的添加映射关系了!

  • 相关阅读:
    ios UIWebView截获html并修改便签内容(转载)
    IOS获取系统时间 NSDate
    ios 把毫秒值转换成日期 NSDate
    iOS  如何判断当前网络连接状态  网络是否正常  网络是否可用
    IOS开发 xcode报错之has been modified since the precompiled header was built
    iOS系统下 的手机屏幕尺寸 分辨率 及系统版本 总结
    iOS 切图使用 分辨率 使用 相关总结
    整合最优雅SSM框架:SpringMVC + Spring + MyBatis 基础
    Java面试之PO,VO,TO,QO,BO
    Notes模板说明
  • 原文地址:https://www.cnblogs.com/Zdelta/p/14122338.html
Copyright © 2011-2022 走看看