zoukankan      html  css  js  c++  java
  • 为Dapper编写一个类似于EF的Map配置类

    引言

    最近在用Dapper处理Sqlite。映射模型的时候不喜欢用Attribute配置,希望用类似EF的Map来配置,所以粗略的实现了一个。

    实现

    首先是主体的配置辅助类型:

    using System;
    using System.Collections.Concurrent;
    using System.Linq.Expressions;
    using System.Reflection;
    using Dapper;
    using DRapid.Utility.Linq.Expressions;
    
    namespace DRapid.Utility.Dapper.Map
    {
        public class InstanceMapper<T> : InstanceMapper
        {
            protected InstanceMapper()
                : base(typeof(T))
            {
    
            }
    
            public static InstanceMapper<T> Config()
            {
                return new InstanceMapper<T>();
            }
    
            public void MapColumn(string columnName, Expression<Func<T, object>> propertySelector)
            {
                var propertyName = ExpressionHelper.ReadMemberName(propertySelector);
                MapColumn(columnName, propertyName);
            }
        }
    
        public class InstanceMapper : SqlMapper.ITypeMap
        {
            protected InstanceMapper(Type type)
            {
                _map = new CustomPropertyTypeMap(type, GetProperty);
                _mapDic = new ConcurrentDictionary<string, PropertyInfo>();
                _instanceType = type;
            }
    
            private CustomPropertyTypeMap _map;
            private Type _instanceType;
            private ConcurrentDictionary<string, PropertyInfo> _mapDic;
    
            public ConstructorInfo FindConstructor(string[] names, Type[] types)
            {
                return _map.FindConstructor(names, types);
            }
    
            public ConstructorInfo FindExplicitConstructor()
            {
                return _map.FindExplicitConstructor();
            }
    
            public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)
            {
                return _map.GetConstructorParameter(constructor, columnName);
            }
    
            public SqlMapper.IMemberMap GetMember(string columnName)
            {
                return _map.GetMember(columnName);
            }
    
            public void MapColumn(string columnName, string propertyName)
            {
                _mapDic.AddOrUpdate(columnName,
                    key => _instanceType.GetProperty(propertyName),
                    (key, pro) => _instanceType.GetProperty(propertyName));
            }
    
            private PropertyInfo GetProperty(Type type, string columnName)
            {
                PropertyInfo propertyInfo;
                var result = _mapDic.TryGetValue(columnName, out propertyInfo);
                return result ? propertyInfo : null;
            }
    
            public void Apply()
            {
                SqlMapper.SetTypeMap(_instanceType, this);
            }
    
            public static InstanceMapper Config(Type type)
            {
                return new InstanceMapper(type);
            }
        }
    }
    
    

    这里是其中引用的一个辅助方法的实现

            public static string ReadMemberName<T>(Expression<Func<T, object>> expression)
            {
                var body = expression.Body;
                /*这里需要考虑转型表达式*/
                if (body.NodeType == ExpressionType.Convert)
                    body = ((UnaryExpression) body).Operand;
                Trace.Assert(body.NodeType == ExpressionType.MemberAccess, "表达式必须是成员访问或者是带转型的成员访问");
                var accessMember = (MemberExpression) body;
                return accessMember.Member.Name;
            }
    

    然后是一些链式调用的扩展支持

    using System;
    using System.Linq.Expressions;
    
    namespace DRapid.Utility.Dapper.Map
    {
        public static class InstanceMapperExtension
        {
            public static InstanceMapper<T> Use<T>(this InstanceMapper<T> mapper, string columnName, string propertyName)
            {
                mapper.MapColumn(columnName, propertyName);
                return mapper;
            }
    
            public static InstanceMapper<T> Use<T>(this InstanceMapper<T> mapper, string columnName,
                Expression<Func<T, object>> propertySelector)
            {
                mapper.MapColumn(columnName, propertySelector);
                return mapper;
            }
        }
    }
    
    

    调用

    由于有静态访问入口,所以配置一般分布在各个类的静态构造函数中,从而防止重复配置。
    所以,对于一个dto类型:

            public class PointInfo
            {
                public byte[] Detail { get; set; }
    
                public double Latitude { get; set; }
    
                public double Longitude { get; set; }
    
                public int Count { get; set; }
            }
    

    可以使用以下配置代码进行配置:

            InstanceMapper<PointInfo>.Config()
                    .Use("STATLG", s => s.Longitude)
                    .Use("STATLA", s => s.Latitude)
                    .Use("FREQUERYCOUNT", s => s.Count)
                    .Use("FREQDB", s => s.Detail)
                    .Apply();
    

    结束。

  • 相关阅读:
    kafka 官方 Quickstart
    oracle11.2 安装
    Perl参考函数/教程
    Mysql参见SHOW命令总结
    MySQL的Innodb缓存相关优化
    Oracle、Mysql和SQL Server数据库连接的URL写法
    jredis 客户端 使用
    sql基本命令-存储过程
    NoSql系列目录ElasticSearch-mongodb
    loadrunner 运行场景-Controller及Load Generators宿主主机优化
  • 原文地址:https://www.cnblogs.com/lightluomeng/p/5556053.html
Copyright © 2011-2022 走看看