mysql 查询父子关系_查询父子关系 · dotnetcore/FreeSql Wiki · GitHub
无限级分类(父子)是一种比较常用的表设计,每种设计方式突出优势的同时也带来缺陷,如:
方法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相关推荐
- mysql 查询存储过程 速度_查询mysql过程
MySql 使用explain分析查询 今天写了个慢到哭的查询,想用explain分析下执行计划,后来发现explain也是有局限性的: EXPLAIN不会告诉你关于触发器.存储过程的信息或用户自定义 ...
- mysql查询高于平均_查询成绩高于平均分的成绩记录。
[简答题]常用的数据库模型有哪些 [单选题]两相接地短路故障时,三序网连接方式是: [单选题]视图存放在_________. [单选题]下列关于触发器的描述中,正确的是. [填空题]_________ ...
- 数据库与python的关系_数据库 引用关系
<深入解析sas:数据处理.分析优化与商业应用>一2.4 访问关系型数据库系统中的数据 本节书摘来自华章出版社<深入解析sas:数据处理.分析优化与商业应用>一书中的第2章,第 ...
- 本地mysql无法监听_查询数据库出错,监听器无法监听
查询数据库出错,监听器无法监听0 a.jsp 项目组在岗员工统计表 项目组名 显示全部 本地人员 出差人员 总计 大连外包 request.setCharacterEncoding("gb2 ...
- mysql sql数据排名_查询数据排名情况SQL
查询数据排名情况SQL 1/准备测试数据 ------------------------------------------------------------------------------- ...
- mysql查询学生姓名_查询全体学生的姓名及其出生年份 (数据库)
在学生信息表中新增字段"专业名称"."年龄" 1.查询全体学生的姓名及其出生年份 2.查询计算机专业的专业号 3.查询所有年龄大于19岁的学生信息 4.查询所有 ...
- mysql取去年年初_查询年初,年末,去年年初,明年年初与年末sql语句
查询年初,年末,去年年初,明年年初与年末sql语句 查询年初,年末,去年年初,明年年初与年末sql语句 --年度计算 declare @date datetime set @date=getdate( ...
- mysql中查看图片_查询已存入数据库中的图片,并显示出来
思路:在存的时候同时存入其图片信息.查询时可以直接调用并显示. BOOL Load(CString sFilePathName); BOOL Load(UINT ResourceName, LPCST ...
- mysql第四章表单查询样题_查询mysql表单中前10条,然后在li中循环输出。
$mysql_servername = "localhost"; $mysql_username = "root"; $mysql_password =&quo ...
- mysql怎么生成可执行文件_查询mysql数据库的java程序在myeclipse上运行正常,但生成可执行文件后查询不出结果。问题出在哪儿呢?...
展开全部 你所说的可执行文件,就是jar包吗?e69da5e6ba903231313335323631343130323136353331333337613164 自己生成的jar文件,执行需要指明所 ...
最新文章
- Android adb 串口调试
- 10-03视图的优缺点及注意事项
- Java中的==和equals区别
- Android官方开发文档Training系列课程中文版:连接无线设备之网络服务搜索功能
- sublime text安装插件出现问题
- Okay 第一篇文章从java字符串开始
- Oracle v$session/v$sql 表
- mysql 全连接_mysql 实现全连接
- eclipse反编译调试源码调试
- HackTheBox You know racecar 格式化字符串漏洞pwn题目
- 如何实现阿里云服务器数据迁移?
- HBuilder打包App教程
- idea显示Multiple Spring Boot run configurations were detected. Services allows to manage multiple run
- Koa2实现电影微信公众号前后端开发学习视频
- 从TOP100summit看产品设计和运营创新的“B”计划和“C”计划
- 新一代光学工程仿真软件FRED MPC介绍
- 3dsMax如何渲染模型
- Python获取Win7,Win10系统缩放大小
- 抖音取图小程序,同款抖音壁纸,表情包小程序搭建
- 解决在启动VirtualBox虚拟机时出现“未能启动虚拟电脑Ubuntu,由于下述物理网卡未找到:”的错误