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中,方便的添加映射关系了!

  • 相关阅读:
    隐式马尔科夫模型
    TCP与UDP协议
    语法分析
    requests发送HTTP请求
    IPv6协议
    IP协议
    路由协议
    Django表单验证
    PDB调试Python程序
    word2vec模型原理与实现
  • 原文地址:https://www.cnblogs.com/Zdelta/p/14122338.html
Copyright © 2011-2022 走看看