FreeSql是一个支持.NET Core 2.1+、.NET Framework 4.0+ 以及 Xamarin的ORM(Object Relational Mapping)对象关系映射的组件

支持丰富的表达式函数及类型映射,但还是有不少开发者需要执行自定义SQL。

我一般会推荐他们使用

List<T> list = fsql.Ado.Query<T>("select * from t1");

等类似的操作,IAdo下有大量的ADO.NET基础的调用操作。但开发者还想使用类似Page,Skip,OrderBy等方法。鉴于fsql可以生成SQL,可以将不同的SQL组合,实现更加复杂的功能。

  • 引用包
dotnet add packages FreeSql
dotnet add packages FreeSql.Provider.Sqlite
  • .NET Core 单例 Startup.cs
public void ConfigureServices(IServiceCollection services)
{
IFreeSql fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=db1.db")
.UseAutoSyncStructure(true) //自动同步实体结构到数据库,FreeSql不会扫描程序集,只有CRUD时才会生成表。
.Build();
services.AddSingleton<IFreeSql>(fsql);
}

可使用以下方式实现

WithSql 自定义SQL

定义实体类

    public class TestClass
{
[Column(Name = "ID", IsPrimary = true)]
public string No { get; set; }
public int? Age { get; set; }
public string Name { get; set; }
[Column(Name = "BIRTH_DAY")]
public DateTime? Birthday { get; set; }
public decimal Point { get; set; }
public Sex? Sex { get; set; }
}
public class TestClssDto
{
public string ID { get; set; } public int? Age { get; set; }
}

不同的查询方式。

  • 返回DataTable
  • 返回List<Tuplue>List<(string,string)>元组
  • 返回List<object> 且能支持分页
  • 返回List<TestClassDto>且能支持分页

1.返回DataTable

DataTable dt1 = _fsql.Select<object>()
.WithSql("select * from TestClass ")
.ToDataTable("ID,Age");
SELECT ID,Age
FROM(select * from TestClass ) a

2.返回DataTable

DataTable dt2 = _fsql.Select<object>()
.WithSql("select * from TestClass ")
.ToDataTable("*");
SELECT *
FROM ( select * from TestClass ) a

3.返回List<Tuplue>List<(string,string)> 元组

List<(string,string)> list1 = _fsql.Select<object>()
.WithSql("select * from TestClass ")
.ToList<(string, string)>("ID,Age");
SELECT ID, Age
FROM(select * from TestClass ) a

4.返回List<object>

var list2 = _fsql.Select<object>()
.WithSql("select * from TestClass ")
.ToList<object>("*");
SELECT *
FROM(select * from TestClass ) a

5.返回List<object> 且能支持分页

  var list3 = _fsql.Select<object>().WithSql("select * from TestClass ")
.WhereIf(true, "1=1")
.Page(1, 10).OrderBy("ID DESC").ToList<object>("ID,Age");
SELECT ID, Age
FROM(select * from TestClass ) a
WHERE(1 = 1)
ORDER BY ID DESC
limit 0,10

6.返回List<TestClassDto>且能支持分页

var list4 = _fsql.Select<object>().WithSql("select * from TestClass ")
.WhereIf(true, "1=1")
.Page(1, 10)
.OrderBy("ID DESC")
.ToList<TestClssDto>("ID,Age");
SELECT ID, Age
FROM(select * from TestClass ) a
WHERE(1 = 1)
ORDER BY ID DESC
limit 0,10

通过 WithSql+ ToSQL实现 Union ALL 查询方法

1、二次 ISelect 查询:WithSql 使用多次,等于 UNION ALL 查询

WithSql 使用多次为 UNION ALL 查询,所以我们可以利用 ISelect.ToSql(FieldAliasOptions.AsProperty) 得到生成的 SQL,如下:

var sql1 = fsql.Select<Topic>()
.Where(a => a.Title.Contains("xxx"))
.ToSql();
var sql2 = fsql.Select<Topic>()
.Where(a => a.Title.Contains("yyy"))
.ToSql(); fsql.Select<Topic>()
.WithSql(sql1)
.WithSql(sql2)
.ToList();
SELECT  * from (SELECT a.`Id`, a.`Clicks`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
FROM ( SELECT a.`Id`, a.`Clicks`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
FROM `tb_topic` a
WHERE ((a.`Title`) LIKE '%xxx%') ) a) ftb UNION ALL SELECT * from (SELECT a.`Id`, a.`Clicks`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
FROM ( SELECT a.`Id`, a.`Clicks`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
FROM `tb_topic` a
WHERE ((a.`Title`) LIKE '%yyy%') ) a) ftb

2、跨分表查询:AsTable 相同实体多次操作,等于 Union ALL 查询

var sql = fsql.Select<User>()
.AsTable((type, oldname) => "table_1")a
.AsTable((type, oldname) => "table_2")
.ToSql(a => a.Id);
select * from (SELECT a."Id" as1 FROM "table_1" a) ftb
UNION ALL
select * from (SELECT a."Id" as1 FROM "table_2" a) ftb

3、利用 ToSql 拼接新的 SQL,使用 IAdo 执行

var sql1 = fsql.Select<Topic>()
.Where(a => a.Id > 100 && a.Id < 200)
.ToSql(a => new { a.Id, a.Title }, FieldAliasOptions.AsProperty);
var sql2 = fsql.Select<Topic>()
.Where(a => a.Id > 1001 && a.Id < 1200)
.ToSql(a => new { a.Id, a.Title }, FieldAliasOptions.AsProperty); fsql.Ado.CommandFluent($"{sql1} UNION ALL {sql2}")
.ExecuteDataTable();

分页问题

Union All 之后 如果直接 分页会有一个问题。请看具体示例

多次WithSql+Page存在问题:每个WithSql内都有一个Page分页

var sql1 = fsql.Select<Topic>()
.Where(a => a.Title.Contains("xxx"))
.ToSql();
var sql2 = fsql.Select<Topic>()
.Where(a => a.Title.Contains("yyy"))
.ToSql(); fsql.Select<Topic>().WithSql(sql1).WithSql(sql2).Page(1, 20).ToList();
 SELECT  * from (SELECT a.`Id`, a.`Clicks`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
FROM ( SELECT a.`Id`, a.`Clicks`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
FROM `tb_topic` a
WHERE ((a.`Title`) LIKE '%xxx%') ) a
limit 0,20) ftb UNION ALL SELECT * from (SELECT a.`Id`, a.`Clicks`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
FROM ( SELECT a.`Id`, a.`Clicks`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
FROM `tb_topic` a
WHERE ((a.`Title`) LIKE '%yyy%') ) a
limit 0,20) ftb

多个sql union all使用withsql,直接Page分页,会导致每个子表都生效,子表都生成分页。

WithSql 可以和 AsTable 实现分表的功能。

分表跨表查询的时候,分页是要向每个子表(即每个WithSql中的SQL分页)都生效。

解决方案

多次withsql,如需分页,需要按下面的二步操作

  • 第一步:通过witsql,将二个sql组成一个sql。
 var sql = fsql.Select<Topic>()
.WithSql("SELECT * FROM tb_topic where id > 11")
.WithSql("SELECT * FROM tb_topic where id < 10")
.ToSql("*")

如上生成的UOION ALL的sql

 SELECT  * from (SELECT *
FROM ( SELECT * FROM tb_topic where id > 11 ) a) ftb UNION ALL SELECT * from (SELECT *
FROM ( SELECT * FROM tb_topic where id < 10 ) a) ftb
  • 第二步:之后 调用Page则是通过Union ALL后的结果上分页
 var sql2 = g.mysql.Select<Topic>()
.WithSql(sql)
.Page(2, 10)
.ToSql();
SELECT a.`Id`, a.`Clicks`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
FROM ( SELECT * from (SELECT *
FROM ( SELECT * FROM tb_topic where id > 11 ) a) ftb UNION ALL SELECT * from (SELECT *
FROM ( SELECT * FROM tb_topic where id < 10 ) a) ftb ) a
limit 10,10

更多

FreeSql使用WithSql+ ToSQL 查询数据的更多相关文章

  1. FreeSql (十五)查询数据

    FreeSql在查询数据下足了功能,链式查询语法.多表查询.表达式函数支持得非常到位. IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnect ...

  2. FreeSql (五)插入数据

    var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + "Initia ...

  3. FreeSql (七)插入数据时忽略列

    var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + "Initia ...

  4. FreeSql (八)插入数据时指定列

    插入数据时指定列,和忽略列对应,未被指定的列将被忽略. var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Passwor ...

  5. FreeSql (九)删除数据

    删除是一个非常危险的操作,FreeSql对删除支持并不强大,仅支持了单表有条件的删除方法. 不想过多的介绍拉长删除数据的系列文章,删除数据的介绍仅此一篇. 若Where条件为空的时候执行方法,Free ...

  6. FreeSql (十)更新数据

    FreeSql支持丰富的更新数据方法,支持单条或批量更新,在特定的数据库执行还可以返回更新后的记录值. var connstr = "Data Source=127.0.0.1;Port=3 ...

  7. FreeSql (十一)更新数据 Where

    var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + "Initia ...

  8. FreeSql (十三)更新数据时忽略列

    var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + "Initia ...

  9. FreeSql 使用 ToTreeList/AsTreeCte 查询无限级分类表

    关于无限级分类 第一种方案: 使用递归算法,也是使用频率最多的,大部分开源程序也是这么处理,不过一般都只用到四级分类. 这种算法的数据库结构设计最为简单.category表中一个字段id,一个字段fi ...

随机推荐

  1. hdu1556 线段树段更新(简单题)

    题意: N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"牌电动车从气球a开始到气球b依次给每个 ...

  2. 3.PHP条件语句及其字符串相关函数

    PHP条件语句 <?php    $number = rand(1,100);    if($number % 2 == 0){        echo "%2";    } ...

  3. springmvc Date类型转换

    有时候我们会碰到这么一个问题,有一个实体类,里面有一个Date类型的数据,jsp页面传递的时间参数是String的,这就导致无法对应,springmvc无法帮我们自动封装参数到实体类中了,这里我解决的 ...

  4. CentOS安装Redis报错[server.o] Error 1

    原因 准备安装的Redis服务版本为6.0.8, gcc的版本为4.8.5,可能是gcc版本过低到导致的 解决办法 安装低版本Redis或者安装高版本gcc

  5. 数据库增量日志监听canal

    概述 canal是阿里巴巴旗下的一款开源项目,纯Java开发.基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了MySQL(也支持mariaDB). 起源:早期,阿里巴巴B2B公司 ...

  6. Mybatis学习之自定义持久层框架(四) 自定义持久层框架:生产sqlSession

    前言 上一回我们完成了数据库配置文件的读取和解析工作,有了这些准备工作,我们就可以与数据库创建连接和会话了,所谓sqlSession就是数据库的会话,一切增删查改操作都是在与数据库的会话中完成,下面我 ...

  7. Scrum Meeting 0

    Basic Info where:五号教学楼 when:2020/4/21 target: 明确每次会议基本流程 简要汇报一下已完成任务,下一步计划与遇到的问题 Progress Team Membe ...

  8. Beta设计和计划 —— NameNotFound

    需求再分析 1. 用户群体 经过用户(大多数是同学)的反馈,我们发现大家其实并不是十分明确我们要做的到底是什么.具体要怎么用.而实际上我们的典型用户也并不是学生群体,因此出现这些偏差也是很正常的,毕竟 ...

  9. shell脚本就是由Shell命令组成的执行文件,将一些命令整合到一个文件中,进行处理业务逻辑,脚本不用编译即可运行。它通过解释器解释运行,所以速度相对来说比较慢。

    shell脚本?在说什么是shell脚本之前,先说说什么是shell. shell是外壳的意思,就是操作系统的外壳.我们可以通过shell命令来操作和控制操作系统,比如Linux中的Shell命令就包 ...

  10. 011.Python的列表的相关操作

    一 列表的相关操作 1.1  列表的拼接 lst1 = [1,2,3] lst2 = [4,5,6] res = lst1 + lst2 print(res) 执行 [root@node10 pyth ...