写在开头

众所周知 Dapper 是 .NET 下最轻最快的 ORM,它是喜欢写 SQL 码农的福音,相对于 SqlHelper 它更加方便,据统计 10个 .NETer 有 9个 用过 Dapper。

由于 .NET 环境的特殊,对 Lambda 表达式树的喜爱,于是市面上有很多出现了基于 Dapper 的轻量级 ORM,它们几乎都有共同特点,让 Dapper 支持 Lambda 表达式树,写起来顺畅如流水。

今天介绍一款本身功能已经很强大的 ORM,他提供一个隐藏得比较深的 API 功能,使用起来和 Dapper 没什么两样。

了解 Lambda 表达式树

这要先从 Lambda 表达式开始说起,词语中少了一个“树”字,差别甚大。

表达式,如下各种语法糖骚操作,产生的 IL 一模一样:

//使用C# 2.0中的匿名方法获取字符串长度
Func<string, int> strLength = delegate(string str) { return str.Length; };
Console.WriteLine(strLength("Hello World!")); //使用Lambda表达式
//(显式类型参数列表)=> {语句},lambda表达式最冗长版本
strLength = (string str) => { return str.Length; };
Console.WriteLine(strLength("Hello World!")); //单一表达式作为主体
//(显式类型参数列表)=> 表达式
strLength = (string str) => str.Length;
Console.WriteLine(strLength("Hello World!")); //隐式类型的参数列表
//(隐式类型参数列表)=> 表达式
strLength = (str) => str.Length;
Console.WriteLine(strLength("Hello World!")); //单一参数的快捷语法
//参数名 => 表达式
strLength = str => str.Length;
Console.WriteLine(strLength("Hello World!"));

而表达式树呢,代码写起来跟表达式差不多,如下:

Expression<Func<string, int>> strLength = str => str.Length;

表达式树不支持代码块(花括号)

力求书写简单,一般情况我们都是这样写的,虽然它和表达式代码写起来几乎一样,但是返回值和表达式不一样,多了一个泛型 Expression<>。

表达式树也称表达式目录树,将代码以一种抽象的方式表示成一个对象树,树中每个节点本身都是一个表达式。表达式树不是可执行代码,它是一种数据结构。它是代码在编译期间将编写的代码转换成一个树结构,以便后续进行逆向解析。

如上:(strLength.Body as MemberExpression).Member.Name 可以得到值 "Length"

由于表达式树可逆向解析的特点,近十年来 EF 是一直是带头大哥,国产每年都要整出好几个 ORM,大部分都是基于表达式树解析做的。

表达式树解析

.NET 技术文章从来不缺少表达式树解析的这类文章,有兴趣的可以百度搜索一下,很多很多,但是想做完美可不是件简单事。

FreeSql 在表达式树解析上做了下足了工夫,举例:

1、子表 in 查询

.Where(a => fsql.Select<T>().ToList(b => b.Id).Contains(a.Id))
//WHERE a.Id in (select id from t)

2、子表 exists 查询

.Where(a => fsql.Select<T>().Any(b => b.Id == a.Id))
//WHERE exists(select 1 from t where Id = a.Id)

3、日期格式化

ToList(a => a.CreateTime.ToString("HH:mm:ss")
//date_format(a.`CreateTime`, '%H:%i:%s')

4、开窗函数

ToList(a => SqlExt.Rank().Over().OrderBy(a.Id).OrderByDescending(b.EdiId).ToValue())
//rank() over(order by a.Id, b.EdiId desc)

5、Join 子表

ToList(a => string.Join(",", fsql.Select<StringJoin01>().ToList(b => b.Id)))
//(SELECT group_concat(b.`Id` separator ',') FROM `StringJoin01` b)

这些特性在不同的数据库,都需要做相应适配实现,FreeSql 还支持对导航属性的表达式树解析,说这些只想证明做到细致真的不容易。

与其自己造着麻烦,不如直接拿来主义使用?

Ado.Net 扩展实现

与其自己造着麻烦,不如直接拿来主义使用?FreeSql 提供了一种非主打的 API 使用习惯,使用起来跟 Dapper 没什么区别。

支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/达梦/神通/人大金仓/翰高/MsAccess 十多种数据库适配,并且支持 .NetFramework 4.0 平台、.NET5.0、.NET Core2.1 + 平台。

第一步:以数据库 SqlServer 访问为例,只需要安装已经划分好的小包:

dotnet add packages FreeSql.Provider.SqlServer

or

Install-Package FreeSql.Provider.SqlServer

第二步:建立实体类

class TestConnectionExt {
public Guid id { get; set; }
public string title { get; set; }
public DateTime createTime { get; set; } = DateTime.Now;
}

第三步:开始 CRUD

using (var conn = new SqlConnection(connectString)) {
var list = conn.Select<TestConnectionExt>().Where(a => a.id == item.id).ToList();
} using (var conn = new SqlConnection(connectString)) {
var item = new TestConnectionExt { title = "testinsert" };
var affrows = conn.Insert(item).ExecuteAffrows();
} using (var conn = new SqlConnection(connectString)) {
var affrows = conn.Update<TestConnectionExt>()
.Where(a => a.Id == xxx)
.Set(a => a.title, "testupdated")
.ExecuteAffrows();
} using (var conn = new SqlConnection(connectString)) {
var affrows = conn.Delete<TestConnectionExt>()
.Where(a => a.Id == xxx)
.ExecuteAffrows();
}

添加或更新:

using (var conn = new SqlConnection(connectString)) {
var affrows = conn.InsertOrUpdate<TestConnectionExt>()
.SetSource(item)
.ExecuteAffrows();
}

如上添加、删除、修改、查询,已经支持实体类操作,并且支持批量插入、批量更新、批量删除、多表查询、导航属性查询。

可以享用 FreeSql 几乎所有功能。

结束语

FreeSql 使用世界上最宽松的开源协议 MIT 托管于 github:https://github.com/dotnetcore/FreeSql 目前已发布经历两年高频率迭代的稳定版本 v2.0,欢迎关注和使用。

支持 .NetFramework 4.0+、.NetCore 2.1+、Xamarin 等支持 NetStandard 所有运行平台。

支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/达梦/神通/人大金仓/翰高/MsAccess 数据库。

QQ群:4336577(已满)、8578575(在线)、52508226(在线)

喜欢 Dapper 的朋友看过来,送一份厚礼的更多相关文章

  1. 在Centos上面用yum不能安装redis的朋友看过来

    我得是centos 6.3,如果直接用yum安装redis,报错,如下:[root@CentOS6 etc]# yum install redisLoaded plugins: fastestmirr ...

  2. PS2手柄在arduino上进行测试,可用,供喜欢diy的朋友借鉴

    #include <PS2X_lib.h> //PS2手柄PS2X ps2x; // create PS2 Controller Class//////////PS2引脚///////// ...

  3. 5年后,我们为什么要从 Entity Framework 转到 Dapper 工具?

    前言 时间退回到 2009-09-26,为了演示开源项目 FineUI 的使用方法,我们发布了 AppBox(通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块),最初的 ...

  4. 如何将 Dapper 换成 SqlSuagr ORM

    为什么要写这篇文章 因数我看到很多人虽然用着SqlSugar,但是同时也用着Dapper,因为SqlSugar兼容了Dapper所有API,所以既然你用了SqlSugar那么就没有必要在同一个项目中使 ...

  5. 使用轻量级ORM Dapper进行增删改查

      项目背景 前一段时间,开始做一个项目,在考虑数据访问层是考虑技术选型,考虑过原始的ADO.NET.微软的EF.NH等.再跟经理讨论后,经理强调不要用Ef,NH做ORM,后期的sql优化不好做,公司 ...

  6. 为什么喜欢Kindle

    为什么喜欢Kindle 有朋友问为什么那么多人喜欢用Kindle,作为刚入手一台Kindle PaperWhite 2 的人, 我想说:这个东西,应该算今年我买的最值得的设备了.它的好处太多了:1:轻 ...

  7. 从HTML Components的衰落看Web Components的危机 HTML Components的一些特性 JavaScript什么叫端到端组件 自己对Polymer的意见

    http://blog.jobbole.com/77837/ 原文出处: 徐飞(@民工精髓V) 搞前端时间比较长的同学都会知道一个东西,那就是HTC(HTML Components),这个东西名字很现 ...

  8. Dapper进行增删改查 z

    http://www.cnblogs.com/huangkaiyan10/p/4640548.html 项目背景 前一段时间,开始做一个项目,在考虑数据访问层是考虑技术选型,考虑过原始的ADO.NET ...

  9. python高级—— 从趟过的坑中聊聊爬虫、反爬以及、反反爬,附送一套高级爬虫试题

    前言: 时隔数月,我终于又更新博客了,然而,在这期间的粉丝数也就跟着我停更博客而涨停了,唉 是的,我改了博客名,不知道为什么要改,就感觉现在这个名字看起来要洋气一点. 那么最近到底咋不更新博客了呢?说 ...

随机推荐

  1. 怎么解决Git中出现 "LF will be replaced by CRLF" 警告

    Windows中使用CRLF标识一行的结束,而在Linux/UNIX系统中只使用LF标识一行的结束.CRLF即Carriage-Return Line-Feed的缩写.通常情况下,Git库不会自动修改 ...

  2. 老师问学生while判断

    老师问学生,这道题你会做了吗?如果学生答"会了(y)",则可以放学.如果学生不会做(n),则老师再讲一遍,再问学生是否会做了...... (1)直到学生会为止,才可以放学. (2) ...

  3. JS函数命名规范

    语法规范: 任何合法的javascript标识符都可以作为函数的名称. 约定俗成的内容:(非ECMAScript语法,但是为了便于开发者理解和识别,约定的函数命名规范.) 命名方法: 小驼峰式命名法 ...

  4. idea开发工具下,进行多个线程切换调试

  5. Linux 升级内核开启 TCP BBR 有多大好处

    前言 如果你有订阅一些科技新闻,应该会有看过内核在4.9当中加入了一个新的算法,来解决在有一定的丢包率的情况下的带宽稳定的问题,这个是谷歌为我们带来的干货,新的 TCP 拥塞控制算法 BBR (Bot ...

  6. kettle——作业

    使用作业执行之前的转换,并且额外在表student2中添加一条数据 这里操作类似hue (1)新建一个作业,拉取组件 选择start 组件名字,类型可以下拉如图,根据需要选择即可 选择转换 并将sta ...

  7. [LeetCode题解]109. 有序链表转换二叉搜索树 | 快慢指针 + 递归

    题目描述 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定的有序链表: ...

  8. 5、Spring Boot缓存

    1.JSR107 Java Caching定义了5个核心接口,分别是CachingProvider.CacheManager.Cache.Entry.Expiry. CachingProvider:定 ...

  9. 【进阶之路】Redis基础知识两篇就满足(二)

    导言 大家好,我是南橘,一名练习时常两年半的java练习生,这是我在博客园的第二篇文章,当然,都是要从别处搬运过来的,不过以后新的文章也会在博客园同步发布,希望大家能多多支持^_^ 这篇文章的出现,首 ...

  10. 通过一道CTF学习HTTP协议请求走私

    HTTP请求走私 HTTP请求走私 HTTP请求走私是针对于服务端处理一个或者多个接收http请求序列的方式,进行绕过安全机制,实施未授权访问一种攻击手段,获取敏感信息,并直接危害其他用户. 请求走私 ...