• PostgreSQL Array 数组类型与 FreeSql 打出一套【组合拳】


    前言

    PostgreSQL 是世界公认的功能最强大的开源数据库,除了基础数据类型 int4/int8/varchar/numeric/timestamp 等,还支持 int4[]/int8[]/varchar[]/numeric[]/timestamp[] 数组类型、hstore 类型(类似 c# Dictionary<string, string>)、gis 类型。

    选择一项技术一定是可以帮助我们提升效率,并且使用一定是非常简便的,才能让我们赚取更多时间,早点下班甚至上班摸鱼。这篇文章主要讲数组类型,如何与 FreeSql 打出简便高效的【组合拳】。

    PostgreSQL 可以为每一种类型创建数组,比如 int4 对应的数组类型是 int4[]、varchar 对应的数据类型是 varchar[]。

    PostgreSQL 虽然支持多维数组,但是不建议使用,因为实际使用中会带来很多操作麻烦,违背了使用简便的初衷。一维数组足够应付很多场景。

    FreeSql 本身已经支持五种导航属性,OneToOne/ManyToOne/OneToMany/ManyToMany/Parent,为它们量身打造了级联保存、贪婪加载、延迟加载、级联删除(递归)、CTE递归查询等功能。

    今天 FreeSql 为 PostgreSQL Array 数组类型提供了第六种新的导航属性 PgArrayToMany 专属功能。


    数组映射

    FreeSql 支持 int[] 映射 int4[]

    string[] 映射 varchar[]

    DateTime[] 映射 timestamp[]

    class Model
    {
        public Guid Id { get; set; }
        public int[] TypeIds { get; set; }
        public Guid[] UserIds { get; set; }
    }
    

    等等,常用的类型都可以直接用数组进行映射,之后就可以像普通类型一样进行 CRUD 操作了。

    var model = new Model
    {
        Id = Guid.NewGuid(),
        TypeIds = new int[] { 1,2,3 },
        UserIds = new Guid[] { Guid.NewGuid(), Guid.NewGuid() }
    };
    fsql.Insert(model).ExecuteAffrows(); //插入
    fsql.Update<Model>().SetSource(model).ExecuteAffrows(); //更新
    fsql.Delete(model).ExecuteAffrows(); //删除
    List<Model> list = fsql.Select<Model>().ToList(); //查询
    

    表达式解析:

    fsql.Select<Model>().Where(a => a.TypeIds.Any()).ToSql();
    fsql.Select<Model>().Where(a => a.TypeIds.Contains(3)).ToSql();
    fsql.Select<Model>().ToSql(a => new
    {
        NewTypeIds = a.TypeIds.Concat(new int [] { 10, 11, 12 })
    });
    fsql.Select<Model>().Where(a => a.TypeIds.Length > 0).ToSql();
    

    如果不够用还可以自定义解析:

    [ExpressionCall]
    public static class DbFunc {
      //必要定义 static + ThreadLocal
      static ThreadLocal<ExpressionCallContext> context = new ThreadLocal<ExpressionCallContext>();
    
      public static DateTime FormatDateTime(this DateTime that, string arg1)
      {
        var up = context.Value;
        if (up.DataType == FreeSql.DataType.PostgreSQL) //重写内容
          up.Result = $"array_xxx({up.ParsedContent["that"]}, {up.ParsedContent["arg1"]})";
        return that;
      }
    }
    
    var sql1 = fsql.Select<Model>()
      .ToSql(a => a.CreateTime.FormatDateTime("xxx"));
    //SELECT array_xxx(a."CreateTime", 'xxx') as1 
    //FROM "Model" a
    

    issues #1145

    Feature 特性:对数组做导航

    简要描述原因:pg 之类的数据库支持数组类型,但是没有对数组做导航支持

    使用场景:避免无必要的中间表

    class User
    {
      public int[] RoleIds { get; set; }
      public Role[] Roles  { get; set; }
    }
    class Role
    {
      public int Id { get; set; }
    }
    

    解决方案

    经过多方需求讨论之后,设定了【功能目标】如下:(已发布版本 v3.2.666-preview20220606)

    功能名称:PostgreSQL 【数组类型】的【导航属性】专属功能

    public enum TableRefType
    {
        OneToOne, ManyToOne, OneToMany, ManyToMany,
        PgArrayToMany //PgArray 专用导航类型
    }
    

    方式一:select * from Role where Id in (RoleIds)

    class User
    {
        public int[] RoleIds { get; set; }
        [Navigate(nameof(RoleIds))]
        public List<Role> Roles { get; set; }
    }
    

    方式二:select * from User where RoleIds @> ARRAY[Id]::int4[]

    class Role
    {
        public int Id { get; set; }
        [Navigate(nameof(User.RoleIds))]
        public List<User> Users { get; set; }
    }
    

    1、支持 LazyLoading 延时加载

    2、支持 IncludeMany、IncludeByPropertyName 贪婪加载

    fsql.Select<User>().IncludeMany(a => a.Roles).ToList();
    fsql.Select<User>().IncludeByPropertyName("Roles").ToList();
    
    fsql.Select<Role>().IncludeMany(a => a.Users).ToList();
    fsql.Select<Role>().IncludeByPropertyName("Users").ToList();
    

    3、支持 Lambda 子查询

    fsql.Select<User>().Where(a => a.Roles.Any(b => b.RoleName == "管理员")).ToList();
    fsql.Select<User>().Where(a => a.Roles.Count() > 0).ToList();
    
    fsql.Select<Role>().Where(a => a.Users.Any(b => b.UserName == "Admin")).ToList();
    fsql.Select<Role>().Where(a => a.Users.Count() > 0).ToList();
    
    //... 以及 AsSelect()
    

    4、不支持级联保存、级联删除(因机制冲突)


    资料补充

    至此,FreeSql 支持了六种导航属性。

    参考资料:FreeSql 五种导航属性进化过程 OneToOne/ManyToOne/OneToMany/ManyToMany/Parent(文章内不包括 PgArrayToMany 介绍)

    FreeSql 是 .Net ORM,能支持 .NetFramework4.0+、.NetCore、Xamarin、XAUI、Blazor、以及还有说不出来的运行平台,因为代码绿色无依赖,支持新平台非常简单。目前单元测试数量:7000+,Nuget下载数量:1000K+,源码几乎每天都有提交。

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

    FreeSql 主要优势在于易用性上,基本是开箱即用,在不同数据库之间切换兼容性比较好。作者花了大量的时间精力在这个项目,肯请您花半小时了解下项目,谢谢。功能特性如下:

    • 支持 CodeFirst 对比结构变化迁移;
    • 支持 DbFirst 从数据库导入实体类;
    • 支持 丰富的表达式函数,自定义解析;
    • 支持 批量添加、批量更新、BulkCopy;
    • 支持 导航属性,贪婪加载、延时加载、级联保存;
    • 支持 读写分离、分表分库,租户设计;
    • 支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/达梦/神通/人大金仓/翰高/MsAccess;

    FreeSql 使用非常简单,只需要定义一个 IFreeSql 对象即可:

    static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
        .UseConnectionString(FreeSql.DataType.MySql, connectionString)
        .UseAutoSyncStructure(true) //自动同步实体结构到数据库
        .Build(); //请务必定义成 Singleton 单例模式
    

    注意:单例不等于线程不安全,除了事务,实际内部是有连接池管理 Ado.net IDbConnection 对象,请放心大胆使用,不用纠结线程安全问题。

    微软制造了优秀的语言 c#,利用语言特性可以做一些非常好用的功能,在 ORM 中使用导航属性非常适合。

    • ManyToOne(N对1) 提供了简单的多表 join 查询;

    • OneToMany(1对N) 提供了简单可控的级联查询、级联保存功能;

    • ManyToMany(多对多) 提供了简单的多对多过滤查询、级联查询、级联保存功能;

    • Parent(父子关系) 提供了常用的 CTE查询、删除、递归功能;

    • PgArrayToMany(数组导航) 提供了 pgsql array 数组类型级联查询;

    希望正在使用的、善良的您能动一动小手指,把文章转发一下,让更多人知道 .NET 有这样一个好用的 ORM 存在。谢谢了!!

    FreeSql 开源协议 MIT https://github.com/dotnetcore/FreeSql,可以商用,文档齐全。QQ群:4336577(已满)、8578575(在线)、52508226(在线)

    如果你有好的 ORM 实现想法,欢迎给作者留言讨论,谢谢观看!

  • 相关阅读:
    jQuery文档操作之删除操作
    jQuery文档操作之修改操作
    jQuery文档操作之克隆操作
    jQuery文档操作之插入操作
    jQuery的使用
    js Demo
    使用jQuery操作input的value值
    Flask-Request
    Flask-Response
    Flask-认识flask
  • 原文地址:https://www.cnblogs.com/FreeSql/p/16351417.html
Copyright © 2020-2023  润新知