mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	- 增加 ISelect.AsTreeCte() 递归查询树表(向下或向下);
This commit is contained in:
		@@ -1754,7 +1754,7 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToTreeList();
 | 
				
			||||||
            Assert.Single(t3);
 | 
					            Assert.Single(t3);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Single(t3[0].Childs);
 | 
					            Assert.Single(t3[0].Childs);
 | 
				
			||||||
@@ -1763,18 +1763,42 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(4, t3.Count);
 | 
					            Assert.Equal(4, t3.Count);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110000", t3[1].Code);
 | 
					            Assert.Equal("110000", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[2].Code);
 | 
					            Assert.Equal("110100", t3[2].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[3].Code);
 | 
					            Assert.Equal("110101", t3[3].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(3, t3.Count);
 | 
					            Assert.Equal(3, t3.Count);
 | 
				
			||||||
            Assert.Equal("110000", t3[0].Code);
 | 
					            Assert.Equal("110000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[1].Code);
 | 
					            Assert.Equal("110100", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[2].Code);
 | 
					            Assert.Equal("110101", t3[2].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var t4 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte(a => a.Name).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("中国", t4[0].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京", t4[1].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 北京市", t4[2].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 东城区", t4[3].path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t4 = fsql.Select<VM_District_Child>().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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Table(Name = "D_District")]
 | 
					        [Table(Name = "D_District")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -889,7 +889,7 @@ FROM ""TB_TOPIC22"" a", subquery);
 | 
				
			|||||||
            var subquery = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToSql();
 | 
					            var subquery = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToSql();
 | 
				
			||||||
            Assert.Equal(@"SELECT a.""ID"", a.""CLICKS"", a.""TYPEGUID"", a.""TITLE"", a.""CREATETIME"" 
 | 
					            Assert.Equal(@"SELECT a.""ID"", a.""CLICKS"", a.""TYPEGUID"", a.""TITLE"", a.""CREATETIME"" 
 | 
				
			||||||
FROM ""TB_TOPIC22"" a 
 | 
					FROM ""TB_TOPIC22"" a 
 | 
				
			||||||
WHERE ((((a.""ID"")::varchar) in (SELECT b.""TITLE"" 
 | 
					WHERE ((((a.""ID"")::text) in (SELECT b.""TITLE"" 
 | 
				
			||||||
	FROM ""TB_TOPIC22"" b)))", subquery);
 | 
						FROM ""TB_TOPIC22"" b)))", subquery);
 | 
				
			||||||
            var subqueryList = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToList();
 | 
					            var subqueryList = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToList();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -1719,7 +1719,7 @@ WHERE ((((a.""ID"")::varchar) in (SELECT b.""TITLE""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToTreeList();
 | 
				
			||||||
            Assert.Single(t3);
 | 
					            Assert.Single(t3);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Single(t3[0].Childs);
 | 
					            Assert.Single(t3[0].Childs);
 | 
				
			||||||
@@ -1728,18 +1728,42 @@ WHERE ((((a.""ID"")::varchar) in (SELECT b.""TITLE""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(4, t3.Count);
 | 
					            Assert.Equal(4, t3.Count);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110000", t3[1].Code);
 | 
					            Assert.Equal("110000", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[2].Code);
 | 
					            Assert.Equal("110100", t3[2].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[3].Code);
 | 
					            Assert.Equal("110101", t3[3].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(3, t3.Count);
 | 
					            Assert.Equal(3, t3.Count);
 | 
				
			||||||
            Assert.Equal("110000", t3[0].Code);
 | 
					            Assert.Equal("110000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[1].Code);
 | 
					            Assert.Equal("110100", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[2].Code);
 | 
					            Assert.Equal("110101", t3[2].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var t4 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte(a => a.Name).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("中国", t4[0].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京", t4[1].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 北京市", t4[2].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 东城区", t4[3].path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t4 = fsql.Select<VM_District_Child>().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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Table(Name = "D_District")]
 | 
					        [Table(Name = "D_District")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1755,7 +1755,7 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToTreeList();
 | 
				
			||||||
            Assert.Single(t3);
 | 
					            Assert.Single(t3);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Single(t3[0].Childs);
 | 
					            Assert.Single(t3[0].Childs);
 | 
				
			||||||
@@ -1764,18 +1764,42 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(4, t3.Count);
 | 
					            Assert.Equal(4, t3.Count);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110000", t3[1].Code);
 | 
					            Assert.Equal("110000", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[2].Code);
 | 
					            Assert.Equal("110100", t3[2].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[3].Code);
 | 
					            Assert.Equal("110101", t3[3].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(3, t3.Count);
 | 
					            Assert.Equal(3, t3.Count);
 | 
				
			||||||
            Assert.Equal("110000", t3[0].Code);
 | 
					            Assert.Equal("110000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[1].Code);
 | 
					            Assert.Equal("110100", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[2].Code);
 | 
					            Assert.Equal("110101", t3[2].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var t4 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte(a => a.Name).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("中国", t4[0].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京", t4[1].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 北京市", t4[2].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 东城区", t4[3].path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t4 = fsql.Select<VM_District_Child>().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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Table(Name = "D_District")]
 | 
					        [Table(Name = "D_District")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -985,7 +985,7 @@ FROM ""tb_topic"" a", subquery);
 | 
				
			|||||||
            var subquery = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToSql();
 | 
					            var subquery = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToSql();
 | 
				
			||||||
            Assert.Equal(@"SELECT a.""id"", a.""clicks"", a.""typeguid"", a.""title"", a.""createtime"" 
 | 
					            Assert.Equal(@"SELECT a.""id"", a.""clicks"", a.""typeguid"", a.""title"", a.""createtime"" 
 | 
				
			||||||
FROM ""tb_topic"" a 
 | 
					FROM ""tb_topic"" a 
 | 
				
			||||||
WHERE ((((a.""id"")::varchar) in (SELECT b.""title"" 
 | 
					WHERE ((((a.""id"")::text) in (SELECT b.""title"" 
 | 
				
			||||||
	FROM ""tb_topic"" b)))", subquery);
 | 
						FROM ""tb_topic"" b)))", subquery);
 | 
				
			||||||
            var subqueryList = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToList();
 | 
					            var subqueryList = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToList();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -1814,7 +1814,7 @@ WHERE ((((a.""id"")::varchar) in (SELECT b.""title""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToTreeList();
 | 
				
			||||||
            Assert.Single(t3);
 | 
					            Assert.Single(t3);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Single(t3[0].Childs);
 | 
					            Assert.Single(t3[0].Childs);
 | 
				
			||||||
@@ -1823,18 +1823,42 @@ WHERE ((((a.""id"")::varchar) in (SELECT b.""title""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(4, t3.Count);
 | 
					            Assert.Equal(4, t3.Count);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110000", t3[1].Code);
 | 
					            Assert.Equal("110000", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[2].Code);
 | 
					            Assert.Equal("110100", t3[2].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[3].Code);
 | 
					            Assert.Equal("110101", t3[3].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(3, t3.Count);
 | 
					            Assert.Equal(3, t3.Count);
 | 
				
			||||||
            Assert.Equal("110000", t3[0].Code);
 | 
					            Assert.Equal("110000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[1].Code);
 | 
					            Assert.Equal("110100", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[2].Code);
 | 
					            Assert.Equal("110101", t3[2].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var t4 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte(a => a.Name).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("中国", t4[0].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京", t4[1].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 北京市", t4[2].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 东城区", t4[3].path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t4 = fsql.Select<VM_District_Child>().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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Table(Name = "D_District")]
 | 
					        [Table(Name = "D_District")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1705,7 +1705,7 @@ WHERE (((cast(a.[Id] as nvarchar(100))) in (SELECT b.[Title]
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToTreeList();
 | 
				
			||||||
            Assert.Single(t3);
 | 
					            Assert.Single(t3);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Single(t3[0].Childs);
 | 
					            Assert.Single(t3[0].Childs);
 | 
				
			||||||
@@ -1714,18 +1714,42 @@ WHERE (((cast(a.[Id] as nvarchar(100))) in (SELECT b.[Title]
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(4, t3.Count);
 | 
					            Assert.Equal(4, t3.Count);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110000", t3[1].Code);
 | 
					            Assert.Equal("110000", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[2].Code);
 | 
					            Assert.Equal("110100", t3[2].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[3].Code);
 | 
					            Assert.Equal("110101", t3[3].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(3, t3.Count);
 | 
					            Assert.Equal(3, t3.Count);
 | 
				
			||||||
            Assert.Equal("110000", t3[0].Code);
 | 
					            Assert.Equal("110000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[1].Code);
 | 
					            Assert.Equal("110100", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[2].Code);
 | 
					            Assert.Equal("110101", t3[2].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var t4 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte(a => a.Name).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("中国", t4[0].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京", t4[1].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 北京市", t4[2].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 东城区", t4[3].path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t4 = fsql.Select<VM_District_Child>().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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Table(Name = "D_District")]
 | 
					        [Table(Name = "D_District")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1755,7 +1755,7 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToTreeList();
 | 
				
			||||||
            Assert.Single(t3);
 | 
					            Assert.Single(t3);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Single(t3[0].Childs);
 | 
					            Assert.Single(t3[0].Childs);
 | 
				
			||||||
@@ -1764,18 +1764,42 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(4, t3.Count);
 | 
					            Assert.Equal(4, t3.Count);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110000", t3[1].Code);
 | 
					            Assert.Equal("110000", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[2].Code);
 | 
					            Assert.Equal("110100", t3[2].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[3].Code);
 | 
					            Assert.Equal("110101", t3[3].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(3, t3.Count);
 | 
					            Assert.Equal(3, t3.Count);
 | 
				
			||||||
            Assert.Equal("110000", t3[0].Code);
 | 
					            Assert.Equal("110000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[1].Code);
 | 
					            Assert.Equal("110100", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[2].Code);
 | 
					            Assert.Equal("110101", t3[2].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var t4 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte(a => a.Name).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("中国", t4[0].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京", t4[1].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 北京市", t4[2].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 东城区", t4[3].path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t4 = fsql.Select<VM_District_Child>().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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Table(Name = "D_District")]
 | 
					        [Table(Name = "D_District")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1755,7 +1755,7 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToTreeList();
 | 
				
			||||||
            Assert.Single(t3);
 | 
					            Assert.Single(t3);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Single(t3[0].Childs);
 | 
					            Assert.Single(t3[0].Childs);
 | 
				
			||||||
@@ -1764,18 +1764,42 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(4, t3.Count);
 | 
					            Assert.Equal(4, t3.Count);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110000", t3[1].Code);
 | 
					            Assert.Equal("110000", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[2].Code);
 | 
					            Assert.Equal("110100", t3[2].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[3].Code);
 | 
					            Assert.Equal("110101", t3[3].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(3, t3.Count);
 | 
					            Assert.Equal(3, t3.Count);
 | 
				
			||||||
            Assert.Equal("110000", t3[0].Code);
 | 
					            Assert.Equal("110000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[1].Code);
 | 
					            Assert.Equal("110100", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[2].Code);
 | 
					            Assert.Equal("110101", t3[2].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var t4 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte(a => a.Name).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("中国", t4[0].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京", t4[1].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 北京市", t4[2].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 东城区", t4[3].path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t4 = fsql.Select<VM_District_Child>().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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Table(Name = "D_District")]
 | 
					        [Table(Name = "D_District")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1002,7 +1002,7 @@ FROM ""tb_topic"" a", subquery);
 | 
				
			|||||||
            var subquery = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToSql();
 | 
					            var subquery = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToSql();
 | 
				
			||||||
            Assert.Equal(@"SELECT a.""id"", a.""clicks"", a.""typeguid"", a.""title"", a.""createtime"" 
 | 
					            Assert.Equal(@"SELECT a.""id"", a.""clicks"", a.""typeguid"", a.""title"", a.""createtime"" 
 | 
				
			||||||
FROM ""tb_topic"" a 
 | 
					FROM ""tb_topic"" a 
 | 
				
			||||||
WHERE ((((a.""id"")::varchar) in (SELECT b.""title"" 
 | 
					WHERE ((((a.""id"")::text) in (SELECT b.""title"" 
 | 
				
			||||||
	FROM ""tb_topic"" b)))", subquery);
 | 
						FROM ""tb_topic"" b)))", subquery);
 | 
				
			||||||
            var subqueryList = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToList();
 | 
					            var subqueryList = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToList();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -1830,7 +1830,7 @@ WHERE ((((a.""id"")::varchar) in (SELECT b.""title""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToTreeList();
 | 
				
			||||||
            Assert.Single(t3);
 | 
					            Assert.Single(t3);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Single(t3[0].Childs);
 | 
					            Assert.Single(t3[0].Childs);
 | 
				
			||||||
@@ -1839,18 +1839,42 @@ WHERE ((((a.""id"")::varchar) in (SELECT b.""title""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(4, t3.Count);
 | 
					            Assert.Equal(4, t3.Count);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110000", t3[1].Code);
 | 
					            Assert.Equal("110000", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[2].Code);
 | 
					            Assert.Equal("110100", t3[2].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[3].Code);
 | 
					            Assert.Equal("110101", t3[3].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(3, t3.Count);
 | 
					            Assert.Equal(3, t3.Count);
 | 
				
			||||||
            Assert.Equal("110000", t3[0].Code);
 | 
					            Assert.Equal("110000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[1].Code);
 | 
					            Assert.Equal("110100", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[2].Code);
 | 
					            Assert.Equal("110101", t3[2].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var t4 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte(a => a.Name).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("中国", t4[0].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京", t4[1].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 北京市", t4[2].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 东城区", t4[3].path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t4 = fsql.Select<VM_District_Child>().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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Table(Name = "D_District")]
 | 
					        [Table(Name = "D_District")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1786,7 +1786,7 @@ WHERE (((cast(a.[Id] as nvarchar(100))) in (SELECT b.[Title]
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToTreeList();
 | 
				
			||||||
            Assert.Single(t3);
 | 
					            Assert.Single(t3);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Single(t3[0].Childs);
 | 
					            Assert.Single(t3[0].Childs);
 | 
				
			||||||
@@ -1795,18 +1795,42 @@ WHERE (((cast(a.[Id] as nvarchar(100))) in (SELECT b.[Title]
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(4, t3.Count);
 | 
					            Assert.Equal(4, t3.Count);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110000", t3[1].Code);
 | 
					            Assert.Equal("110000", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[2].Code);
 | 
					            Assert.Equal("110100", t3[2].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[3].Code);
 | 
					            Assert.Equal("110101", t3[3].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(3, t3.Count);
 | 
					            Assert.Equal(3, t3.Count);
 | 
				
			||||||
            Assert.Equal("110000", t3[0].Code);
 | 
					            Assert.Equal("110000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[1].Code);
 | 
					            Assert.Equal("110100", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[2].Code);
 | 
					            Assert.Equal("110101", t3[2].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var t4 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte(a => a.Name).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("中国", t4[0].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京", t4[1].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 北京市", t4[2].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 东城区", t4[3].path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t4 = fsql.Select<VM_District_Child>().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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Table(Name = "D_District")]
 | 
					        [Table(Name = "D_District")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1904,7 +1904,7 @@ WHERE (((cast(a.""Id"" as character)) in (SELECT b.""Title""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToTreeList();
 | 
				
			||||||
            Assert.Single(t3);
 | 
					            Assert.Single(t3);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Single(t3[0].Childs);
 | 
					            Assert.Single(t3[0].Childs);
 | 
				
			||||||
@@ -1913,18 +1913,42 @@ WHERE (((cast(a.""Id"" as character)) in (SELECT b.""Title""
 | 
				
			|||||||
            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
					            Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
					            Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(4, t3.Count);
 | 
					            Assert.Equal(4, t3.Count);
 | 
				
			||||||
            Assert.Equal("100000", t3[0].Code);
 | 
					            Assert.Equal("100000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110000", t3[1].Code);
 | 
					            Assert.Equal("110000", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[2].Code);
 | 
					            Assert.Equal("110100", t3[2].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[3].Code);
 | 
					            Assert.Equal("110101", t3[3].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList();
 | 
					            t3 = fsql.Select<VM_District_Child>().Where(a => a.Name == "北京").AsTreeCte().OrderBy(a => a.Code).ToList();
 | 
				
			||||||
            Assert.Equal(3, t3.Count);
 | 
					            Assert.Equal(3, t3.Count);
 | 
				
			||||||
            Assert.Equal("110000", t3[0].Code);
 | 
					            Assert.Equal("110000", t3[0].Code);
 | 
				
			||||||
            Assert.Equal("110100", t3[1].Code);
 | 
					            Assert.Equal("110100", t3[1].Code);
 | 
				
			||||||
            Assert.Equal("110101", t3[2].Code);
 | 
					            Assert.Equal("110101", t3[2].Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var t4 = fsql.Select<VM_District_Child>().Where(a => a.Name == "中国").AsTreeCte(a => a.Name).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("中国", t4[0].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京", t4[1].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 北京市", t4[2].path);
 | 
				
			||||||
 | 
					            Assert.Equal("中国 -> 北京 -> 东城区", t4[3].path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t4 = fsql.Select<VM_District_Child>().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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Table(Name = "D_District")]
 | 
					        [Table(Name = "D_District")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -386,16 +386,24 @@ public static partial class FreeSqlGlobalExtensions
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
    #endregion
 | 
					    #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #region WhereTree(..) 递归查询
 | 
					    #region AsTreeCte(..) 递归查询
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 使用递归 CTE 查询树型的所有子数据。<para></para>
 | 
					    /// 使用递归 CTE 查询树型的所有子记录,或者所有父记录。<para></para>
 | 
				
			||||||
    /// 通过测试的数据库:MySql8.0、SqlServer、PostgreSQL、Oracle、Sqlite、达梦、人大金仓
 | 
					    /// 通过测试的数据库:MySql8.0、SqlServer、PostgreSQL、Oracle、Sqlite、达梦、人大金仓<para></para>
 | 
				
			||||||
 | 
					    /// 返回隐藏字段:.ToList(a => new { item = a, level = "a.cte_level", path = "a.cte_path" })
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <typeparam name="T1"></typeparam>
 | 
					    /// <typeparam name="T1"></typeparam>
 | 
				
			||||||
    /// <param name="that"></param>
 | 
					    /// <param name="that"></param>
 | 
				
			||||||
    /// <param name="depth">深度</param>
 | 
					    /// <param name="up">false(默认):由父级向子级的递归查询<para></para>true:由子级向父级的递归查询</param>
 | 
				
			||||||
 | 
					    /// <param name="pathSelector">路径内容选择</param>
 | 
				
			||||||
 | 
					    /// <param name="pathSeparator">连接路径内容</param>
 | 
				
			||||||
 | 
					    /// <param name="level">递归层级</param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public static ISelect<T1> AsCteTree<T1>(this ISelect<T1> that, int depth = -1) where T1 : class
 | 
					    public static ISelect<T1> AsTreeCte<T1>(this ISelect<T1> that,
 | 
				
			||||||
 | 
					        Expression<Func<T1, string>> pathSelector = null,
 | 
				
			||||||
 | 
					        bool up = false,
 | 
				
			||||||
 | 
					        string pathSeparator = " -> ",
 | 
				
			||||||
 | 
					        int level = -1) where T1 : class
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var select = that as Select1Provider<T1>;
 | 
					        var select = that as Select1Provider<T1>;
 | 
				
			||||||
        var tb = select._tables[0].Table;
 | 
					        var tb = select._tables[0].Table;
 | 
				
			||||||
@@ -407,24 +415,66 @@ public static partial class FreeSqlGlobalExtensions
 | 
				
			|||||||
        if (navs.Length != 1) throw new ArgumentException($"{tb.Type.FullName} 不是父子关系,无法使用该功能");
 | 
					        if (navs.Length != 1) throw new ArgumentException($"{tb.Type.FullName} 不是父子关系,无法使用该功能");
 | 
				
			||||||
        var tbref = navs[0];
 | 
					        var tbref = navs[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var cteName = "as_cte_tree";
 | 
					        var cteName = "as_tree_cte";
 | 
				
			||||||
        if (select._orm.CodeFirst.IsSyncStructureToLower) cteName = cteName.ToLower();
 | 
					        if (select._orm.CodeFirst.IsSyncStructureToLower) cteName = cteName.ToLower();
 | 
				
			||||||
        if (select._orm.CodeFirst.IsSyncStructureToUpper) cteName = cteName.ToUpper();
 | 
					        if (select._orm.CodeFirst.IsSyncStructureToUpper) cteName = cteName.ToUpper();
 | 
				
			||||||
        var sql1 = select.ToSql($"0 as as_cte_tree_depth, {select.GetAllFieldExpressionTreeLevel2().Field}").Trim();
 | 
					        var sql1ctePath = "";
 | 
				
			||||||
 | 
					        if (pathSelector != null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            select._tables[0].Parameter = pathSelector?.Parameters[0];
 | 
				
			||||||
 | 
					            switch (select._orm.Ado.DataType)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case DataType.PostgreSQL:
 | 
				
			||||||
 | 
					                case DataType.OdbcPostgreSQL:
 | 
				
			||||||
 | 
					                case DataType.OdbcKingbaseES:
 | 
				
			||||||
 | 
					                case DataType.ShenTong: //神通测试未通过
 | 
				
			||||||
 | 
					                case DataType.SqlServer:
 | 
				
			||||||
 | 
					                case DataType.OdbcSqlServer:
 | 
				
			||||||
 | 
					                    sql1ctePath = select._commonExpression.ExpressionWhereLambda(select._tables, Expression.Call(typeof(Convert).GetMethod("ToString", new Type[] { typeof(string) }), pathSelector?.Body), null, null, null);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                default:
 | 
				
			||||||
 | 
					                    sql1ctePath = select._commonExpression.ExpressionWhereLambda(select._tables, pathSelector?.Body, null, null, null);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            sql1ctePath = $"{sql1ctePath} as cte_path, ";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        var sql1 = select.ToSql($"0 as cte_level, {sql1ctePath}{select.GetAllFieldExpressionTreeLevel2().Field}").Trim();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        select._where.Clear();
 | 
					        select._where.Clear();
 | 
				
			||||||
        select.As("wct2");
 | 
					        select.As("wct2");
 | 
				
			||||||
        var sql2Field = select.GetAllFieldExpressionTreeLevel2().Field;
 | 
					        var sql2Field = select.GetAllFieldExpressionTreeLevel2().Field;
 | 
				
			||||||
 | 
					        var sql2InnerJoinOn = up == false ?
 | 
				
			||||||
 | 
					            string.Join(" and ", tbref.Columns.Select((a, z) => $"wct2.{select._commonUtils.QuoteSqlName(tbref.RefColumns[z].Attribute.Name)} = wct1.{select._commonUtils.QuoteSqlName(a.Attribute.Name)}")) :
 | 
				
			||||||
 | 
					            string.Join(" and ", tbref.Columns.Select((a, z) => $"wct2.{select._commonUtils.QuoteSqlName(a.Attribute.Name)} = wct1.{select._commonUtils.QuoteSqlName(tbref.RefColumns[z].Attribute.Name)}"));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        var sql2ctePath = "";
 | 
				
			||||||
 | 
					        if (pathSelector != null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            select._tables[0].Parameter = pathSelector?.Parameters[0];
 | 
				
			||||||
 | 
					            var wct2ctePath = select._commonExpression.ExpressionWhereLambda(select._tables, pathSelector?.Body, null, null, null);
 | 
				
			||||||
 | 
					            sql2ctePath = select._commonUtils.StringConcat(
 | 
				
			||||||
 | 
					                new string[] {
 | 
				
			||||||
 | 
					                    up == false ? "wct1.cte_path" : wct2ctePath,
 | 
				
			||||||
 | 
					                    select._commonUtils.FormatSql("{0}", pathSeparator),
 | 
				
			||||||
 | 
					                    up == false ? wct2ctePath : "wct1.cte_path"
 | 
				
			||||||
 | 
					                }, new Type[] {
 | 
				
			||||||
 | 
					                    typeof(string),
 | 
				
			||||||
 | 
					                    typeof(string),
 | 
				
			||||||
 | 
					                    typeof(string)
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            sql2ctePath = $"{sql2ctePath} as cte_path, ";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        var sql2 = select
 | 
					        var sql2 = select
 | 
				
			||||||
            .AsAlias((type, old) => type == tb.Type ? old.Replace("wct2", "wct1") : old)
 | 
					            .AsAlias((type, old) => type == tb.Type ? old.Replace("wct2", "wct1") : old)
 | 
				
			||||||
            .AsTable((type, old) => type == tb.Type ? cteName : old)
 | 
					            .AsTable((type, old) => type == tb.Type ? cteName : old)
 | 
				
			||||||
            .InnerJoin($"{select._commonUtils.QuoteSqlName(tb.DbName)} wct2 ON {string.Join(" and ", tbref.Columns.Select((a,z) => $"wct2.{select._commonUtils.QuoteSqlName(tbref.RefColumns[z].Attribute.Name)} = wct1.{select._commonUtils.QuoteSqlName(a.Attribute.Name)}"))}")
 | 
					            .InnerJoin($"{select._commonUtils.QuoteSqlName(tb.DbName)} wct2 ON {sql2InnerJoinOn}")
 | 
				
			||||||
            .ToSql($"wct1.as_cte_tree_depth + 1 as as_cte_tree_depth, {sql2Field}").Trim();
 | 
					            .ToSql($"wct1.cte_level + 1 as cte_level, {sql2ctePath}{sql2Field}").Trim();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var newSelect = select._orm.Select<T1>()
 | 
					        var newSelect = select._orm.Select<T1>()
 | 
				
			||||||
            .AsType(tb.Type)
 | 
					            .AsType(tb.Type)
 | 
				
			||||||
            .AsTable((type, old) => type == tb.Type ? cteName : old)
 | 
					            .AsTable((type, old) => type == tb.Type ? cteName : old)
 | 
				
			||||||
            .WhereIf(depth > 0, $"a.as_cte_tree_depth < {depth + 1}") as Select1Provider<T1>;
 | 
					            .WhereIf(level > 0, $"a.cte_level < {level + 1}")
 | 
				
			||||||
 | 
					            .OrderBy(up, "a.cte_level desc") as Select1Provider<T1>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var nsselsb = new StringBuilder();
 | 
					        var nsselsb = new StringBuilder();
 | 
				
			||||||
        if (AdoProvider.IsFromSlave(select._select) == false) nsselsb.Append(" "); //读写分离规则,如果强制读主库,则在前面加个空格
 | 
					        if (AdoProvider.IsFromSlave(select._select) == false) nsselsb.Append(" "); //读写分离规则,如果强制读主库,则在前面加个空格
 | 
				
			||||||
@@ -447,7 +497,7 @@ public static partial class FreeSqlGlobalExtensions
 | 
				
			|||||||
            case DataType.OdbcOracle:
 | 
					            case DataType.OdbcOracle:
 | 
				
			||||||
            case DataType.Dameng: //递归 WITH 子句必须具有列别名列表
 | 
					            case DataType.Dameng: //递归 WITH 子句必须具有列别名列表
 | 
				
			||||||
            case DataType.OdbcDameng:
 | 
					            case DataType.OdbcDameng:
 | 
				
			||||||
                nsselsb.Append($"(as_cte_tree_depth, {sql2Field.Replace("wct2.", "")})");
 | 
					                nsselsb.Append($"(cte_level, {(pathSelector == null ? "" : "cte_path, ")}{sql2Field.Replace("wct2.", "")})");
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        nsselsb.Append(@"
 | 
					        nsselsb.Append(@"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3653,14 +3653,18 @@
 | 
				
			|||||||
            <param name="that"></param>
 | 
					            <param name="that"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSqlGlobalExtensions.AsCteTree``1(FreeSql.ISelect{``0},System.Int32)">
 | 
					        <member name="M:FreeSqlGlobalExtensions.AsTreeCte``1(FreeSql.ISelect{``0},System.Linq.Expressions.Expression{System.Func{``0,System.String}},System.Boolean,System.String,System.Int32)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            使用递归 CTE 查询树型的所有子数据。<para></para>
 | 
					            使用递归 CTE 查询树型的所有子记录,或者所有父记录。<para></para>
 | 
				
			||||||
            通过测试的数据库:MySql8.0、SqlServer、PostgreSQL、Oracle、Sqlite、达梦、人大金仓
 | 
					            通过测试的数据库:MySql8.0、SqlServer、PostgreSQL、Oracle、Sqlite、达梦、人大金仓<para></para>
 | 
				
			||||||
 | 
					            返回隐藏字段:.ToList(a => new { item = a, level = "a.cte_level", path = "a.cte_path" })
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <typeparam name="T1"></typeparam>
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
            <param name="that"></param>
 | 
					            <param name="that"></param>
 | 
				
			||||||
            <param name="depth">深度</param>
 | 
					            <param name="up">false(默认):由父级向子级的递归查询<para></para>true:由子级向父级的递归查询</param>
 | 
				
			||||||
 | 
					            <param name="pathSelector">路径内容选择</param>
 | 
				
			||||||
 | 
					            <param name="pathSeparator">连接路径内容</param>
 | 
				
			||||||
 | 
					            <param name="level">递归层级</param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:System.Linq.Expressions.LambadaExpressionExtensions.And``1(System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}},System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}})">
 | 
					        <member name="M:System.Linq.Expressions.LambadaExpressionExtensions.And``1(System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}},System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}})">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,7 @@ namespace FreeSql.Odbc.KingbaseES
 | 
				
			|||||||
                            case "System.Int64": return $"({getExp(operandExp)})::int8";
 | 
					                            case "System.Int64": return $"({getExp(operandExp)})::int8";
 | 
				
			||||||
                            case "System.SByte": return $"({getExp(operandExp)})::int2";
 | 
					                            case "System.SByte": return $"({getExp(operandExp)})::int2";
 | 
				
			||||||
                            case "System.Single": return $"({getExp(operandExp)})::float4";
 | 
					                            case "System.Single": return $"({getExp(operandExp)})::float4";
 | 
				
			||||||
                            case "System.String": return $"({getExp(operandExp)})::varchar";
 | 
					                            case "System.String": return $"({getExp(operandExp)})::text";
 | 
				
			||||||
                            case "System.UInt16": return $"({getExp(operandExp)})::int2";
 | 
					                            case "System.UInt16": return $"({getExp(operandExp)})::int2";
 | 
				
			||||||
                            case "System.UInt32": return $"({getExp(operandExp)})::int4";
 | 
					                            case "System.UInt32": return $"({getExp(operandExp)})::int4";
 | 
				
			||||||
                            case "System.UInt64": return $"({getExp(operandExp)})::int8";
 | 
					                            case "System.UInt64": return $"({getExp(operandExp)})::int8";
 | 
				
			||||||
@@ -87,7 +87,7 @@ namespace FreeSql.Odbc.KingbaseES
 | 
				
			|||||||
                            if (callExp.Method.DeclaringType.IsNumberType()) return "random()";
 | 
					                            if (callExp.Method.DeclaringType.IsNumberType()) return "random()";
 | 
				
			||||||
                            return null;
 | 
					                            return null;
 | 
				
			||||||
                        case "ToString":
 | 
					                        case "ToString":
 | 
				
			||||||
                            if (callExp.Object != null) return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::varchar" : null;
 | 
					                            if (callExp.Object != null) return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::text" : null;
 | 
				
			||||||
                            return null;
 | 
					                            return null;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -332,10 +332,10 @@ namespace FreeSql.Odbc.KingbaseES
 | 
				
			|||||||
                            if (exp.Arguments[1].Type == typeof(bool) ||
 | 
					                            if (exp.Arguments[1].Type == typeof(bool) ||
 | 
				
			||||||
                                exp.Arguments[1].Type == typeof(StringComparison) && getExp(exp.Arguments[0]).Contains("IgnoreCase")) likeOpt = "ILIKE";
 | 
					                                exp.Arguments[1].Type == typeof(StringComparison) && getExp(exp.Arguments[0]).Contains("IgnoreCase")) likeOpt = "ILIKE";
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::varchar || '%')")}";
 | 
					                        if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::text || '%')")}";
 | 
				
			||||||
                        if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::varchar)")}";
 | 
					                        if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::text)")}";
 | 
				
			||||||
                        if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
 | 
					                        if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
 | 
				
			||||||
                        return $"({left}) {likeOpt} ('%' || ({args0Value})::varchar || '%')";
 | 
					                        return $"({left}) {likeOpt} ('%' || ({args0Value})::text || '%')";
 | 
				
			||||||
                    case "ToLower": return $"lower({left})";
 | 
					                    case "ToLower": return $"lower({left})";
 | 
				
			||||||
                    case "ToUpper": return $"upper({left})";
 | 
					                    case "ToUpper": return $"upper({left})";
 | 
				
			||||||
                    case "Substring":
 | 
					                    case "Substring":
 | 
				
			||||||
@@ -378,7 +378,7 @@ namespace FreeSql.Odbc.KingbaseES
 | 
				
			|||||||
                        return left;
 | 
					                        return left;
 | 
				
			||||||
                    case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
					                    case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
				
			||||||
                    case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
 | 
					                    case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
 | 
				
			||||||
                    case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::varchar)";
 | 
					                    case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::text)";
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
@@ -573,7 +573,7 @@ namespace FreeSql.Odbc.KingbaseES
 | 
				
			|||||||
                    case "ToInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
					                    case "ToInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
				
			||||||
                    case "ToSByte": return $"({getExp(exp.Arguments[0])})::int2";
 | 
					                    case "ToSByte": return $"({getExp(exp.Arguments[0])})::int2";
 | 
				
			||||||
                    case "ToSingle": return $"({getExp(exp.Arguments[0])})::float4";
 | 
					                    case "ToSingle": return $"({getExp(exp.Arguments[0])})::float4";
 | 
				
			||||||
                    case "ToString": return $"({getExp(exp.Arguments[0])})::varchar";
 | 
					                    case "ToString": return $"({getExp(exp.Arguments[0])})::text";
 | 
				
			||||||
                    case "ToUInt16": return $"({getExp(exp.Arguments[0])})::int2";
 | 
					                    case "ToUInt16": return $"({getExp(exp.Arguments[0])})::int2";
 | 
				
			||||||
                    case "ToUInt32": return $"({getExp(exp.Arguments[0])})::int4";
 | 
					                    case "ToUInt32": return $"({getExp(exp.Arguments[0])})::int4";
 | 
				
			||||||
                    case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
					                    case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,7 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
                            case "System.Int64": return $"({getExp(operandExp)})::int8";
 | 
					                            case "System.Int64": return $"({getExp(operandExp)})::int8";
 | 
				
			||||||
                            case "System.SByte": return $"({getExp(operandExp)})::int2";
 | 
					                            case "System.SByte": return $"({getExp(operandExp)})::int2";
 | 
				
			||||||
                            case "System.Single": return $"({getExp(operandExp)})::float4";
 | 
					                            case "System.Single": return $"({getExp(operandExp)})::float4";
 | 
				
			||||||
                            case "System.String": return $"({getExp(operandExp)})::varchar";
 | 
					                            case "System.String": return $"({getExp(operandExp)})::text";
 | 
				
			||||||
                            case "System.UInt16": return $"({getExp(operandExp)})::int2";
 | 
					                            case "System.UInt16": return $"({getExp(operandExp)})::int2";
 | 
				
			||||||
                            case "System.UInt32": return $"({getExp(operandExp)})::int4";
 | 
					                            case "System.UInt32": return $"({getExp(operandExp)})::int4";
 | 
				
			||||||
                            case "System.UInt64": return $"({getExp(operandExp)})::int8";
 | 
					                            case "System.UInt64": return $"({getExp(operandExp)})::int8";
 | 
				
			||||||
@@ -87,7 +87,7 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
                            if (callExp.Method.DeclaringType.IsNumberType()) return "random()";
 | 
					                            if (callExp.Method.DeclaringType.IsNumberType()) return "random()";
 | 
				
			||||||
                            return null;
 | 
					                            return null;
 | 
				
			||||||
                        case "ToString":
 | 
					                        case "ToString":
 | 
				
			||||||
                            if (callExp.Object != null) return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::varchar" : null;
 | 
					                            if (callExp.Object != null) return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::text" : null;
 | 
				
			||||||
                            return null;
 | 
					                            return null;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -354,10 +354,10 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
                            if (exp.Arguments[1].Type == typeof(bool) ||
 | 
					                            if (exp.Arguments[1].Type == typeof(bool) ||
 | 
				
			||||||
                                exp.Arguments[1].Type == typeof(StringComparison) && getExp(exp.Arguments[0]).Contains("IgnoreCase")) likeOpt = "ILIKE";
 | 
					                                exp.Arguments[1].Type == typeof(StringComparison) && getExp(exp.Arguments[0]).Contains("IgnoreCase")) likeOpt = "ILIKE";
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::varchar || '%')")}";
 | 
					                        if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::text || '%')")}";
 | 
				
			||||||
                        if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::varchar)")}";
 | 
					                        if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::text)")}";
 | 
				
			||||||
                        if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
 | 
					                        if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
 | 
				
			||||||
                        return $"({left}) {likeOpt} ('%' || ({args0Value})::varchar || '%')";
 | 
					                        return $"({left}) {likeOpt} ('%' || ({args0Value})::text || '%')";
 | 
				
			||||||
                    case "ToLower": return $"lower({left})";
 | 
					                    case "ToLower": return $"lower({left})";
 | 
				
			||||||
                    case "ToUpper": return $"upper({left})";
 | 
					                    case "ToUpper": return $"upper({left})";
 | 
				
			||||||
                    case "Substring":
 | 
					                    case "Substring":
 | 
				
			||||||
@@ -405,7 +405,7 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
                        return left;
 | 
					                        return left;
 | 
				
			||||||
                    case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
					                    case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
				
			||||||
                    case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
 | 
					                    case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
 | 
				
			||||||
                    case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::varchar)";
 | 
					                    case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::text)";
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
@@ -598,7 +598,7 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
                    case "ToInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
					                    case "ToInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
				
			||||||
                    case "ToSByte": return $"({getExp(exp.Arguments[0])})::int2";
 | 
					                    case "ToSByte": return $"({getExp(exp.Arguments[0])})::int2";
 | 
				
			||||||
                    case "ToSingle": return $"({getExp(exp.Arguments[0])})::float4";
 | 
					                    case "ToSingle": return $"({getExp(exp.Arguments[0])})::float4";
 | 
				
			||||||
                    case "ToString": return $"({getExp(exp.Arguments[0])})::varchar";
 | 
					                    case "ToString": return $"({getExp(exp.Arguments[0])})::text";
 | 
				
			||||||
                    case "ToUInt16": return $"({getExp(exp.Arguments[0])})::int2";
 | 
					                    case "ToUInt16": return $"({getExp(exp.Arguments[0])})::int2";
 | 
				
			||||||
                    case "ToUInt32": return $"({getExp(exp.Arguments[0])})::int4";
 | 
					                    case "ToUInt32": return $"({getExp(exp.Arguments[0])})::int4";
 | 
				
			||||||
                    case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
					                    case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,8 @@ namespace FreeSql.Odbc.SqlServer
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                if (types[a] == typeof(string)) news[a] = objs[a];
 | 
					                if (types[a] == typeof(string)) news[a] = objs[a];
 | 
				
			||||||
                else if (types[a].NullableTypeOrThis() == typeof(Guid)) news[a] = $"cast({objs[a]} as char(36))";
 | 
					                else if (types[a].NullableTypeOrThis() == typeof(Guid)) news[a] = $"cast({objs[a]} as char(36))";
 | 
				
			||||||
                else news[a] = $"cast({objs[a]} as nvarchar)";
 | 
					                else if (types[a].IsNumberType()) news[a] = $"cast({objs[a]} as varchar)";
 | 
				
			||||||
 | 
					                else news[a] = $"cast({objs[a]} as nvarchar(max))";
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return string.Join(" + ", news);
 | 
					            return string.Join(" + ", news);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,7 @@ namespace FreeSql.PostgreSQL
 | 
				
			|||||||
                            case "System.Int64": return $"({getExp(operandExp)})::int8";
 | 
					                            case "System.Int64": return $"({getExp(operandExp)})::int8";
 | 
				
			||||||
                            case "System.SByte": return $"({getExp(operandExp)})::int2";
 | 
					                            case "System.SByte": return $"({getExp(operandExp)})::int2";
 | 
				
			||||||
                            case "System.Single": return $"({getExp(operandExp)})::float4";
 | 
					                            case "System.Single": return $"({getExp(operandExp)})::float4";
 | 
				
			||||||
                            case "System.String": return $"({getExp(operandExp)})::varchar";
 | 
					                            case "System.String": return $"({getExp(operandExp)})::text";
 | 
				
			||||||
                            case "System.UInt16": return $"({getExp(operandExp)})::int2";
 | 
					                            case "System.UInt16": return $"({getExp(operandExp)})::int2";
 | 
				
			||||||
                            case "System.UInt32": return $"({getExp(operandExp)})::int4";
 | 
					                            case "System.UInt32": return $"({getExp(operandExp)})::int4";
 | 
				
			||||||
                            case "System.UInt64": return $"({getExp(operandExp)})::int8";
 | 
					                            case "System.UInt64": return $"({getExp(operandExp)})::int8";
 | 
				
			||||||
@@ -88,7 +88,7 @@ namespace FreeSql.PostgreSQL
 | 
				
			|||||||
                            if (callExp.Method.DeclaringType.IsNumberType()) return "random()";
 | 
					                            if (callExp.Method.DeclaringType.IsNumberType()) return "random()";
 | 
				
			||||||
                            return null;
 | 
					                            return null;
 | 
				
			||||||
                        case "ToString":
 | 
					                        case "ToString":
 | 
				
			||||||
                            if (callExp.Object != null) return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::varchar" : null;
 | 
					                            if (callExp.Object != null) return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::text" : null;
 | 
				
			||||||
                            return null;
 | 
					                            return null;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -120,7 +120,7 @@ namespace FreeSql.PostgreSQL
 | 
				
			|||||||
                                    case "Contains":
 | 
					                                    case "Contains":
 | 
				
			||||||
                                        var json = getExp(callExp.Arguments[argIndex]);
 | 
					                                        var json = getExp(callExp.Arguments[argIndex]);
 | 
				
			||||||
                                        if (objType == typeof(JArray))
 | 
					                                        if (objType == typeof(JArray))
 | 
				
			||||||
                                            return $"(coalesce({left},'[]') ? ({json})::varchar)";
 | 
					                                            return $"(coalesce({left},'[]') ? ({json})::text)";
 | 
				
			||||||
                                        if (json.StartsWith("'") && json.EndsWith("'"))
 | 
					                                        if (json.StartsWith("'") && json.EndsWith("'"))
 | 
				
			||||||
                                            return $"(coalesce({left},'{{}}') @> {_common.FormatSql("{0}", JToken.Parse(json.Trim('\'')))})";
 | 
					                                            return $"(coalesce({left},'{{}}') @> {_common.FormatSql("{0}", JToken.Parse(json.Trim('\'')))})";
 | 
				
			||||||
                                        return $"(coalesce({left},'{{}}') @> ({json})::jsonb)";
 | 
					                                        return $"(coalesce({left},'{{}}') @> ({json})::jsonb)";
 | 
				
			||||||
@@ -385,10 +385,10 @@ namespace FreeSql.PostgreSQL
 | 
				
			|||||||
                            if (exp.Arguments[1].Type == typeof(bool) ||
 | 
					                            if (exp.Arguments[1].Type == typeof(bool) ||
 | 
				
			||||||
                                exp.Arguments[1].Type == typeof(StringComparison) && getExp(exp.Arguments[0]).Contains("IgnoreCase")) likeOpt = "ILIKE";
 | 
					                                exp.Arguments[1].Type == typeof(StringComparison) && getExp(exp.Arguments[0]).Contains("IgnoreCase")) likeOpt = "ILIKE";
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::varchar || '%')")}";
 | 
					                        if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::text || '%')")}";
 | 
				
			||||||
                        if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::varchar)")}";
 | 
					                        if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::text)")}";
 | 
				
			||||||
                        if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
 | 
					                        if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
 | 
				
			||||||
                        return $"({left}) {likeOpt} ('%' || ({args0Value})::varchar || '%')";
 | 
					                        return $"({left}) {likeOpt} ('%' || ({args0Value})::text || '%')";
 | 
				
			||||||
                    case "ToLower": return $"lower({left})";
 | 
					                    case "ToLower": return $"lower({left})";
 | 
				
			||||||
                    case "ToUpper": return $"upper({left})";
 | 
					                    case "ToUpper": return $"upper({left})";
 | 
				
			||||||
                    case "Substring":
 | 
					                    case "Substring":
 | 
				
			||||||
@@ -436,7 +436,7 @@ namespace FreeSql.PostgreSQL
 | 
				
			|||||||
                        return left;
 | 
					                        return left;
 | 
				
			||||||
                    case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
					                    case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
				
			||||||
                    case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
 | 
					                    case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
 | 
				
			||||||
                    case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::varchar)";
 | 
					                    case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::text)";
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
@@ -629,7 +629,7 @@ namespace FreeSql.PostgreSQL
 | 
				
			|||||||
                    case "ToInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
					                    case "ToInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
				
			||||||
                    case "ToSByte": return $"({getExp(exp.Arguments[0])})::int2";
 | 
					                    case "ToSByte": return $"({getExp(exp.Arguments[0])})::int2";
 | 
				
			||||||
                    case "ToSingle": return $"({getExp(exp.Arguments[0])})::float4";
 | 
					                    case "ToSingle": return $"({getExp(exp.Arguments[0])})::float4";
 | 
				
			||||||
                    case "ToString": return $"({getExp(exp.Arguments[0])})::varchar";
 | 
					                    case "ToString": return $"({getExp(exp.Arguments[0])})::text";
 | 
				
			||||||
                    case "ToUInt16": return $"({getExp(exp.Arguments[0])})::int2";
 | 
					                    case "ToUInt16": return $"({getExp(exp.Arguments[0])})::int2";
 | 
				
			||||||
                    case "ToUInt32": return $"({getExp(exp.Arguments[0])})::int4";
 | 
					                    case "ToUInt32": return $"({getExp(exp.Arguments[0])})::int4";
 | 
				
			||||||
                    case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
					                    case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,7 +85,8 @@ namespace FreeSql.SqlServer
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                if (types[a] == typeof(string)) news[a] = objs[a];
 | 
					                if (types[a] == typeof(string)) news[a] = objs[a];
 | 
				
			||||||
                else if (types[a].NullableTypeOrThis() == typeof(Guid)) news[a] = $"cast({objs[a]} as char(36))";
 | 
					                else if (types[a].NullableTypeOrThis() == typeof(Guid)) news[a] = $"cast({objs[a]} as char(36))";
 | 
				
			||||||
                else news[a] = $"cast({objs[a]} as nvarchar)";
 | 
					                else if (types[a].IsNumberType()) news[a] = $"cast({objs[a]} as varchar)";
 | 
				
			||||||
 | 
					                else news[a] = $"cast({objs[a]} as nvarchar(max))";
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return string.Join(" + ", news);
 | 
					            return string.Join(" + ", news);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user