引言

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

实现

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

  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Linq.Expressions;
  4. using System.Reflection;
  5. using Dapper;
  6. using DRapid.Utility.Linq.Expressions;
  7. namespace DRapid.Utility.Dapper.Map
  8. {
  9. public class InstanceMapper<T> : InstanceMapper
  10. {
  11. protected InstanceMapper()
  12. : base(typeof(T))
  13. {
  14. }
  15. public static InstanceMapper<T> Config()
  16. {
  17. return new InstanceMapper<T>();
  18. }
  19. public void MapColumn(string columnName, Expression<Func<T, object>> propertySelector)
  20. {
  21. var propertyName = ExpressionHelper.ReadMemberName(propertySelector);
  22. MapColumn(columnName, propertyName);
  23. }
  24. }
  25. public class InstanceMapper : SqlMapper.ITypeMap
  26. {
  27. protected InstanceMapper(Type type)
  28. {
  29. _map = new CustomPropertyTypeMap(type, GetProperty);
  30. _mapDic = new ConcurrentDictionary<string, PropertyInfo>();
  31. _instanceType = type;
  32. }
  33. private CustomPropertyTypeMap _map;
  34. private Type _instanceType;
  35. private ConcurrentDictionary<string, PropertyInfo> _mapDic;
  36. public ConstructorInfo FindConstructor(string[] names, Type[] types)
  37. {
  38. return _map.FindConstructor(names, types);
  39. }
  40. public ConstructorInfo FindExplicitConstructor()
  41. {
  42. return _map.FindExplicitConstructor();
  43. }
  44. public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)
  45. {
  46. return _map.GetConstructorParameter(constructor, columnName);
  47. }
  48. public SqlMapper.IMemberMap GetMember(string columnName)
  49. {
  50. return _map.GetMember(columnName);
  51. }
  52. public void MapColumn(string columnName, string propertyName)
  53. {
  54. _mapDic.AddOrUpdate(columnName,
  55. key => _instanceType.GetProperty(propertyName),
  56. (key, pro) => _instanceType.GetProperty(propertyName));
  57. }
  58. private PropertyInfo GetProperty(Type type, string columnName)
  59. {
  60. PropertyInfo propertyInfo;
  61. var result = _mapDic.TryGetValue(columnName, out propertyInfo);
  62. return result ? propertyInfo : null;
  63. }
  64. public void Apply()
  65. {
  66. SqlMapper.SetTypeMap(_instanceType, this);
  67. }
  68. public static InstanceMapper Config(Type type)
  69. {
  70. return new InstanceMapper(type);
  71. }
  72. }
  73. }

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

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

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

  1. using System;
  2. using System.Linq.Expressions;
  3. namespace DRapid.Utility.Dapper.Map
  4. {
  5. public static class InstanceMapperExtension
  6. {
  7. public static InstanceMapper<T> Use<T>(this InstanceMapper<T> mapper, string columnName, string propertyName)
  8. {
  9. mapper.MapColumn(columnName, propertyName);
  10. return mapper;
  11. }
  12. public static InstanceMapper<T> Use<T>(this InstanceMapper<T> mapper, string columnName,
  13. Expression<Func<T, object>> propertySelector)
  14. {
  15. mapper.MapColumn(columnName, propertySelector);
  16. return mapper;
  17. }
  18. }
  19. }

调用

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

所以,对于一个dto类型:

  1. public class PointInfo
  2. {
  3. public byte[] Detail { get; set; }
  4. public double Latitude { get; set; }
  5. public double Longitude { get; set; }
  6. public int Count { get; set; }
  7. }

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

  1. InstanceMapper<PointInfo>.Config()
  2. .Use("STATLG", s => s.Longitude)
  3. .Use("STATLA", s => s.Latitude)
  4. .Use("FREQUERYCOUNT", s => s.Count)
  5. .Use("FREQDB", s => s.Detail)
  6. .Apply();

结束。

为Dapper编写一个类似于EF的Map配置类的更多相关文章

  1. Java连接MySQL数据库。编写一个应用程序,在主类Test_4类中,通过JDBC访问stu数据库,显示t_student表中的内容(表结构见表1),显示效果自己设计。

    题目2:编写一个应用程序,在主类Test_4类中,通过JDBC访问stu数据库,显示t_student表中的内容(表结构见表1),显示效果自己设计.之后,可根据显示的内容进行某条记录的删除(以id为条 ...

  2. 编写一个应用程序,在主类Test1类中,创建两个链表List<E>对象,分别存储通过键盘输入的字符串内容

    题目1:编写一个应用程序,在主类Test1类中,创建两个链表List<E>对象,分别存储通过键盘输入的字符串内容--"chen","wang",&q ...

  3. property_自己编写一个读取Property文件的Util类

    读取property文件的Util类: 所需jar包: 编写PropertiesUtil类: package com.west.util.property; import java.io.InputS ...

  4. 16.按要求编写Java应用程序。 编写一个名为Test的主类,类中只有一个主方法; 在主方法中定义一个大小为50的一维整型数组,数组名为x,数组中存放着{1, 3,5,…,99}输出这个数组中的所有元素,每输出十个换一行;在主方法中定义一 个大小为10*10的二维字符型数组,数组名为y,正反对角线上存的是‘*’,其余 位置存的是‘#’;输出这个数组中的所有元素。

    //分类 package com.bao; public class Shuchu { int[]yi=new int[50]; String[][]er=new String[10][10]; vo ...

  5. 按要求编写Java应用程序。 编写一个名为Test的主类,类中只有一个主方法; 在主方法中定义一个大小为50的一维整型数组,数组名为x,数组中存放着{1, 3,5,…,99}输出这个数组中的所有元素,每输出十个换一行;在主方法中定义一 个大小为10*10的二维字符型数组,数组名为y,正反对角线上存的是‘*’,其余 位置存的是‘#’;输出这个数组中的所有元素。

    int[]x=new int [50]; char[][]y=new char[10][10]; int j=1,w=0; for(int i=0;i<50;i++) { x[i]=j; j+= ...

  6. 编写一个名为Test的主类,类中只有一个主方法; 在主方法中定义一个大小为50的一维整型数组,数组名为x,数组中存放着{1, 3,5,…,99}输出这个数组中的所有元素,每输出十个换一行;在主方法中定义一 个大小为10*10的二维字符型数组,数组名为y,正反对角线上存的是‘*’,其余 位置存的是‘#’;输出这个数组中的所有元素。

    package liu0915; import java.util.Random; public class Test0915sz { public static void main(String[] ...

  7. 编写一个Filter,除继承HttpServlet类外还需要( )。

    A.继承Filter 类 B.实现Filter 接口 C.继承HttpFilter 类 D.实现HttpFilter接口 解答:B

  8. 【1】按照Django官网,编写一个web app 创建project/配置数据库

    1. Creating a project From the command line, cd into a directory where you'd like to store your code ...

  9. 13)编写一个子类SnakeCtrl来继承基类

    1)首先是创建子类SnakeCtrl 2)     添加那个SnakeCtrl子类 3)出来了SnakeCtrl的基本样子 4)简单实现: ①改编那个SnakeCtrl.h中的内容: #pragma ...

随机推荐

  1. jQuery API 3.1.0 速查表-打印版

    jQuery API 3.1.0 速查表-打印图,(API来自:http://jquery.cuishifeng.cn/index.html)

  2. 北大ACM(POJ1753-Flip Game)

    Question:http://poj.org/problem?id=1753 问题点:穷举. #include <iostream> using namespace std; ][];/ ...

  3. 制作BibTex文件

    上一篇日志中讲到了在LaTeX中使用BibTex管理参考文献,这篇日志具体总结下如何制作BibTex文件. 制作BibTex文件,主要有以下几种方法: 手工制作: 直接从期刊数据库中下载: 借助Goo ...

  4. crackme_zapline分析

    [破文标题]crackme_zapline 分析 [破文作者]CloAk [作者邮箱]@qq.com [作者主页] [破解工具]OD,... [破解平台]Windows --------------- ...

  5. Swift使用闭包表达式

    Swift中的闭包表达式很灵活,其标准语法格式如下:{ (参数列表) ->返回值类型 in    语句组}其中,参数列表与函数中的参数列表形式一样,返回值类型类似于函数中的返回值类型,但不同的是 ...

  6. 在windows7中使用计划任务命令SCHTASKS查询计划任务失败的解决方案

    造成这种原因是因为编码问题: 因此需要修改编码:chcp schtasks.exe /query 会报错     错误: 无法加载列资源. 修改编码为936为436就可以允许啦,但是中文不不能显示啦. ...

  7. jQuery中的getter和setter方法

    1.attr()方法是jQuery中用于HTML属性的getter/setter.一个相关函数是removeAttr(). 2.css()方法和attr()方法很类似,只是css()方法作用于元素的c ...

  8. 【leetcode】8. String to Integer (atoi)

    题目描述: Implement atoi to convert a string to an integer. Hint: Carefully consider all possible input ...

  9. [ZZ+CH] Html5 canvas+js 时钟

    总之新Blog入驻以后,又开始老习惯,到处折腾自定义的空间,放些东西. 想起以前大一的时候做过一个Javascript的时间显示器,现在想做一个时钟,当然现在老奸巨猾,会先去看一看有前辈写过没. 前辈 ...

  10. jquery文字左右滚动

    实现jquery文字左右滚动 <div class="fl">中奖名单:</div> <div class="scrollText" ...