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
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); }
可使用以下方式实现
定义实体类
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>
且能支持分页DataTable dt1 = _fsql.Select<object>() .WithSql("select * from TestClass ") .ToDataTable("ID,Age");
SELECT ID,Age FROM(select * from TestClass ) a
DataTable dt2 = _fsql.Select<object>() .WithSql("select * from TestClass ") .ToDataTable("*");
SELECT * FROM ( select * from TestClass ) a
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
List<object>
var list2 = _fsql.Select<object>() .WithSql("select * from TestClass ") .ToList<object>("*");
SELECT * FROM(select * from TestClass ) a
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
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 使用多次为 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
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
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 之后 如果直接 分页会有一个问题。请看具体示例
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分页)都生效。
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
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