我偶然听说sqlsugar的性能比dapper强。对此我表示怀疑(由于我一直使用的dapper存在偏见吧),于是自己测试了sqlsugar、freesql、dapper发现他们的给我的结果是
sqlsugar>dapper>freesql(这里并不是黑那个orm,毕竟不同orm功能不同,底层实现不同,适用场景不同性能当然不同)。这让我很吃惊,dapper(号称orm king)一个执行sql的映射器,比不了基于linq语法的sqlsugar。同时也让我感到高兴,我高兴的是:orm的性能肯定还有提升的空间。
于是我便开始研究它们并着手编写。最终以一千行左右的代码量实现了dapper的基本映射功能,性能真正意义接近ado.net
对比于dapper的底层存在拆装箱操作(我的没有,请看IL),强制类型转换,dapper内置各种缓存(缓存就要考虑并发安全,就要用lock),许多功能并不是我们所需要的,一些功能又是我们迫切需要的,dapper有些定制化功能我们要查阅很多资料才能实现。浪费我们宝贵的时间,dapper对匿名类型支持并不好,这阻碍的我的另一个框架dapper.common(dapper的linq实现方案,将来要移植到sqlcommon),我让作者改一下,支持一下,作者认为linq映射也不是dapper所需要的功能,不予支持。
自己动手丰衣足食,那么我们完全可以自己编写一套。
性能测试
下面进行简要实现:
完整源码地址:https://github.com/1448376744/SqlCommon
nuget也发布了v1.0.0
1.我们要如何实现?我们要实现的第一个问题是DataReader对象转实体类,用反射肯定不行。我们需要用IL来动态创建下面的函数
我们可以创建这样的函数,通过IL来动态创建,大致的过程
创建实体类型->判断实体类型中的属性在reader中是否存在->如果存在则对该字段赋值
1.我们定义一个接口,,因为匹配C#字段和数据库字段名之间有一个映射规则(是否区分大小写,是否忽略下划线等等)
第一个接口要求我们传递一个类型的所有属性,和要绑定的列信息
第二个查找一个类型的转换方法(比如字段属性的bool,我们一个返回一个bool类型的转换函数)
第三个是用于处理匿名类型的,不细说了
第四个返回一个类型的构造器
我们编写一套实现
然后实现一下DataConvertMethod(FindConvertMethod需要)这里是缩减版
然后我们编写IL来创建动态函数,并使用用上面的接口作为参数
动态创建的IL绑定函数我们需要编写一个缓存策略(我们使用hash结构进行存储),一个目标类型可能生成多个绑定函数,这根据你sql返回的字段个数和顺序有关
定义hash结构的key
好了大部分工作都完成了,我们编一个sql执行器(简化版)
至此我们已经完成了整个流程。
我们可以发现没有拆装箱,没有强制类型转换,
对比于使用ado.net的性能差距,由于我们的动态生成绑定函数,在下次使用的时候我们需要从hash表中去查询这个函数指针。
这便是性能的差距点,而我们首先绑定函数,下次时候的时候显示的调用你定义的绑定函数。
也就是说,你只要能优化这个缓存策略,就能无限接近手写ado.net。
原文链接:https://www.cnblogs.com/chaeyeon/p/11615863.html
.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com