无限级分类(父子)是一种比较常用的表设计,每种设计方式突出优势的同时也带来缺陷,如:

方法1:表设计中只有 parent_id 字段,困扰:查询麻烦(本文可解决);

方法2:表设计中冗余子级id便于查询,困扰:添加/更新/删除的时候需要重新计算;

方法3:表设计中存储左右值编码,困扰:同上;

方法1设计最简单,本文解决它的递归查询问题,让使用透明化。

父子导航属性

FreeSql 导航属性之中,有针对父子关系的设置方式,如下:

public class Area

{

[Column(IsPrimary = true)]

public string Code { get; set; }

public string Name { get; set; }

public string ParentCode { get; set; }

[Navigate(nameof(ParentCode))]

public Area Parent { get; set; }

[Navigate(nameof(ParentCode))]

public List Childs { get; set; }

}

定义 Parent 属性,在表达式中可以这样:

fsql.Select().Where(a => a.Parent.Parent.Parent.Name == "中国").First();

定义 Childs 属性,在表达式中可以这样(子查询):

fsql.Select().Where(a => a.Childs.AsSelect().Any(c => c.Name == "北京")).First();

定义 Childs 属性,还可以使用【级联保存】、【贪婪加载】 等等操作。

fsql.Delete().Where("1=1").ExecuteAffrows();

var repo = fsql.GetRepository();

repo.DbContextOptions.EnableAddOrUpdateNavigateList = true;

repo.DbContextOptions.NoneParameter = true;

repo.Insert(new Area

{

Code = "100000",

Name = "中国",

Childs = new List(new[] {

new Area

{

Code = "110000",

Name = "北京",

Childs = new List(new[] {

new Area{ Code="110100", Name = "北京市" },

new Area{ Code="110101", Name = "东城区" },

})

}

})

});

1、ToTreeList

配置好父子属性之后,就可以这样用了:

var t1 = fsql.Select().ToTreeList();

Assert.Single(t1);

Assert.Equal("100000", t1[0].Code);

Assert.Single(t1[0].Childs);

Assert.Equal("110000", t1[0].Childs[0].Code);

Assert.Equal(2, t1[0].Childs[0].Childs.Count);

Assert.Equal("110100", t1[0].Childs[0].Childs[0].Code);

Assert.Equal("110101", t1[0].Childs[0].Childs[1].Code);

查询数据本来是平面的,ToTreeList 方法将返回的平面数据在内存中加工为树型 List 返回。

2、AsTreeCte 递归删除

很常见的无限级分类表功能,删除树节点时,把子节点也处理一下。

fsql.Select()

.Where(a => a.Name == "中国")

.AsTreeCte()

.ToDelete()

.ExecuteAffrows(); //删除 中国 下的所有记录

如果软删除:

fsql.Select()

.Where(a => a.Name == "中国")

.AsTreeCte()

.ToUpdate()

.Set(a => a.IsDeleted, true)

.ExecuteAffrows(); //软删除 中国 下的所有记录

3、AsTreeCte 递归查询

若不做数据冗余的无限级分类表设计,递归查询少不了,AsTreeCte 正是解决递归查询的封装,方法参数说明:

参数

描述

(可选) pathSelector

路径内容选择,可以设置查询返回:中国 -> 北京 -> 东城区

(可选) up

false(默认):由父级向子级的递归查询,true:由子级向父级的递归查询

(可选) pathSeparator

设置 pathSelector 的连接符,默认:->

(可选) level

设置递归层级

通过测试的数据库:MySql8.0、SqlServer、PostgreSQL、Oracle、Sqlite、Firebird、达梦、人大金仓、翰高

姿势一:AsTreeCte() + ToTreeList

var t2 = fsql.Select()

.Where(a => a.Name == "中国")

.AsTreeCte() //查询 中国 下的所有记录

.OrderBy(a => a.Code)

.ToTreeList(); //非必须,也可以使用 ToList(见姿势二)

Assert.Single(t2);

Assert.Equal("100000", t2[0].Code);

Assert.Single(t2[0].Childs);

Assert.Equal("110000", t2[0].Childs[0].Code);

Assert.Equal(2, t2[0].Childs[0].Childs.Count);

Assert.Equal("110100", t2[0].Childs[0].Childs[0].Code);

Assert.Equal("110101", t2[0].Childs[0].Childs[1].Code);

// WITH "as_tree_cte"

// as

// (

// SELECT 0 as cte_level, a."Code", a."Name", a."ParentCode"

// FROM "Area" a

// WHERE (a."Name" = '中国')

// union all

// SELECT wct1.cte_level + 1 as cte_level, wct2."Code", wct2."Name", wct2."ParentCode"

// FROM "as_tree_cte" wct1

// INNER JOIN "Area" wct2 ON wct2."ParentCode" = wct1."Code"

// )

// SELECT a."Code", a."Name", a."ParentCode"

// FROM "as_tree_cte" a

// ORDER BY a."Code"

姿势二:AsTreeCte() + ToList

var t3 = fsql.Select()

.Where(a => a.Name == "中国")

.AsTreeCte()

.OrderBy(a => a.Code)

.ToList();

Assert.Equal(4, t3.Count);

Assert.Equal("100000", t3[0].Code);

Assert.Equal("110000", t3[1].Code);

Assert.Equal("110100", t3[2].Code);

Assert.Equal("110101", t3[3].Code);

//执行的 SQL 与姿势一相同

姿势三:AsTreeCte(pathSelector) + ToList

设置 pathSelector 参数后,如何返回隐藏字段?

var t4 = fsql.Select()

.Where(a => a.Name == "中国")

.AsTreeCte(a => a.Name + "[" + a.Code + "]")

.OrderBy(a => a.Code)

.ToList(a => new {

item = a,

level = Convert.ToInt32("a.cte_level"),

path = "a.cte_path"

});

Assert.Equal(4, t4.Count);

Assert.Equal("100000", t4[0].item.Code);

Assert.Equal("110000", t4[1].item.Code);

Assert.Equal("110100", t4[2].item.Code);

Assert.Equal("110101", t4[3].item.Code);

Assert.Equal("中国[100000]", t4[0].path);

Assert.Equal("中国[100000] -> 北京[110000]", t4[1].path);

Assert.Equal("中国[100000] -> 北京[110000] -> 北京市[110100]", t4[2].path);

Assert.Equal("中国[100000] -> 北京[110000] -> 东城区[110101]", t4[3].path);

// WITH "as_tree_cte"

// as

// (

// SELECT 0 as cte_level, a."Name" || '[' || a."Code" || ']' as cte_path, a."Code", a."Name", a."ParentCode"

// FROM "Area" a

// WHERE (a."Name" = '中国')

// union all

// SELECT wct1.cte_level + 1 as cte_level, wct1.cte_path || ' -> ' || wct2."Name" || '[' || wct2."Code" || ']' as cte_path, wct2."Code", wct2."Name", wct2."ParentCode"

// FROM "as_tree_cte" wct1

// INNER JOIN "Area" wct2 ON wct2."ParentCode" = wct1."Code"

// )

// SELECT a."Code" as1, a."Name" as2, a."ParentCode" as5, a.cte_level as6, a.cte_path as7

// FROM "as_tree_cte" a

// ORDER BY a."Code"

更多姿势...请根据代码注释进行尝试

参考资料

mysql 查询父子关系_查询父子关系 · dotnetcore/FreeSql Wiki · GitHub相关推荐

  1. mysql 查询存储过程 速度_查询mysql过程

    MySql 使用explain分析查询 今天写了个慢到哭的查询,想用explain分析下执行计划,后来发现explain也是有局限性的: EXPLAIN不会告诉你关于触发器.存储过程的信息或用户自定义 ...

  2. mysql查询高于平均_查询成绩高于平均分的成绩记录。

    [简答题]常用的数据库模型有哪些 [单选题]两相接地短路故障时,三序网连接方式是: [单选题]视图存放在_________. [单选题]下列关于触发器的描述中,正确的是. [填空题]_________ ...

  3. 数据库与python的关系_数据库 引用关系

    <深入解析sas:数据处理.分析优化与商业应用>一2.4 访问关系型数据库系统中的数据 本节书摘来自华章出版社<深入解析sas:数据处理.分析优化与商业应用>一书中的第2章,第 ...

  4. 本地mysql无法监听_查询数据库出错,监听器无法监听

    查询数据库出错,监听器无法监听0 a.jsp 项目组在岗员工统计表 项目组名 显示全部 本地人员 出差人员 总计 大连外包 request.setCharacterEncoding("gb2 ...

  5. mysql sql数据排名_查询数据排名情况SQL

    查询数据排名情况SQL 1/准备测试数据 ------------------------------------------------------------------------------- ...

  6. mysql查询学生姓名_查询全体学生的姓名及其出生年份 (数据库)

    在学生信息表中新增字段"专业名称"."年龄" 1.查询全体学生的姓名及其出生年份 2.查询计算机专业的专业号 3.查询所有年龄大于19岁的学生信息 4.查询所有 ...

  7. mysql取去年年初_查询年初,年末,去年年初,明年年初与年末sql语句

    查询年初,年末,去年年初,明年年初与年末sql语句 查询年初,年末,去年年初,明年年初与年末sql语句 --年度计算 declare @date datetime set @date=getdate( ...

  8. mysql中查看图片_查询已存入数据库中的图片,并显示出来

    思路:在存的时候同时存入其图片信息.查询时可以直接调用并显示. BOOL Load(CString sFilePathName); BOOL Load(UINT ResourceName, LPCST ...

  9. mysql第四章表单查询样题_查询mysql表单中前10条,然后在li中循环输出。

    $mysql_servername = "localhost"; $mysql_username = "root"; $mysql_password =&quo ...

  10. mysql怎么生成可执行文件_查询mysql数据库的java程序在myeclipse上运行正常,但生成可执行文件后查询不出结果。问题出在哪儿呢?...

    展开全部 你所说的可执行文件,就是jar包吗?e69da5e6ba903231313335323631343130323136353331333337613164 自己生成的jar文件,执行需要指明所 ...

最新文章

  1. Android adb 串口调试
  2. 10-03视图的优缺点及注意事项
  3. Java中的==和equals区别
  4. Android官方开发文档Training系列课程中文版:连接无线设备之网络服务搜索功能
  5. sublime text安装插件出现问题
  6. Okay 第一篇文章从java字符串开始
  7. Oracle v$session/v$sql 表
  8. mysql 全连接_mysql 实现全连接
  9. eclipse反编译调试源码调试
  10. HackTheBox You know racecar 格式化字符串漏洞pwn题目
  11. 如何实现阿里云服务器数据迁移?
  12. HBuilder打包App教程
  13. idea显示Multiple Spring Boot run configurations were detected. Services allows to manage multiple run
  14. Koa2实现电影微信公众号前后端开发学习视频
  15. 从TOP100summit看产品设计和运营创新的“B”计划和“C”计划
  16. 新一代光学工程仿真软件FRED MPC介绍
  17. 3dsMax如何渲染模型
  18. Python获取Win7,Win10系统缩放大小
  19. 抖音取图小程序,同款抖音壁纸,表情包小程序搭建
  20. 解决在启动VirtualBox虚拟机时出现“未能启动虚拟电脑Ubuntu,由于下述物理网卡未找到:”的错误

热门文章

  1. 什么是请求报文和响应报文?
  2. 达梦数据库dm8使用心得
  3. 一份让你效率翻倍的年终总结
  4. 国内八家域名注册商优缺点比较(转)
  5. CSS3实现钟表特效
  6. 计算机cad运行缓慢怎样处理,旧电脑如何提高CAD运行速度
  7. 计算机图形学——Liang-Barsky算法
  8. 微分几何为何必然兴起?
  9. 智慧校园人脸识别门禁系统设计方案
  10. Java项目:在线bbs论坛系统(java+SSM+JSP+bootstrap+jQuery+mysql)