• FreeSql使用WithSql+ ToSQL 查询数据


    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
    

    更多

    作者: 、天上有木月OvO

    出处:https://cnblogs.com/igeekfan

    联系:luoyunchong@foxmail.com

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如有问题或建议,请多多赐教,非常感谢。
  • 相关阅读:
    spring-102-spring全注解快速实现事务
    spring-101-springAOP
    spring-201-springmvc基于MappingJacksonValue 实现JSONP
    啥是JSONP---转
    request.getSession(boolean create)的正确使用姿势
    spring-003-Resource资源
    spring-002-Ioc bean配置
    spring-001-Ioc 顶层容器
    为企业提供免费代码安全扫描服务(每月限一次)
    圆满完成平安科技Web安全与App应用安全测试培训!
  • 原文地址:https://www.cnblogs.com/igeekfan/p/FreeSql-WithSql-ORM.html
Copyright © 2020-2023  润新知