diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 4854f49c..132d875e 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -125,13 +125,6 @@ 清空状态数据 - - - 根据 lambda 条件删除数据 - - - - 添加 @@ -486,14 +479,5 @@ - - - 批量注入 Repository,可以参考代码自行调整 - - - - - - diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/MySqlConnector/Curd/MySqlSelectTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/MySqlConnector/Curd/MySqlSelectTest.cs index 554be95f..956d0aaf 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/MySqlConnector/Curd/MySqlSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/MySqlConnector/Curd/MySqlSelectTest.cs @@ -1865,7 +1865,7 @@ WHERE ((b.`IsFinished` OR a.`TaskType` = 3) AND b.`EnabledMark` = 1)", groupsql1 new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1903,6 +1903,28 @@ WHERE ((b.`IsFinished` OR a.`TaskType` = 3) AND b.`EnabledMark` = 1)", groupsql1 Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + //t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + //Assert.Single(t3); + //Assert.Equal("100000", t3[0].Code); + //Assert.Single(t3[0].Childs); + //Assert.Equal("110000", t3[0].Childs[0].Code); + //Assert.Equal(2, t3[0].Childs[0].Childs.Count); + //Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + //Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + //t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + //Assert.Equal(4, t3.Count); + //Assert.Equal("100000", t3[0].Code); + //Assert.Equal("110000", t3[1].Code); + //Assert.Equal("110100", t3[2].Code); + //Assert.Equal("110101", t3[3].Code); + + //t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + //Assert.Equal(3, t3.Count); + //Assert.Equal("110000", t3[0].Code); + //Assert.Equal("110100", t3[1].Code); + //Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Dameng/Curd/DamengSelectTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Dameng/Curd/DamengSelectTest.cs index 20705c2a..6eeafa37 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Dameng/Curd/DamengSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Dameng/Curd/DamengSelectTest.cs @@ -1715,7 +1715,7 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE"" new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1753,6 +1753,28 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE"" Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(4, t3.Count); + Assert.Equal("100000", t3[0].Code); + Assert.Equal("110000", t3[1].Code); + Assert.Equal("110100", t3[2].Code); + Assert.Equal("110101", t3[3].Code); + + t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(3, t3.Count); + Assert.Equal("110000", t3[0].Code); + Assert.Equal("110100", t3[1].Code); + Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/KingbaseES/Curd/KingbaseESSelectTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/KingbaseES/Curd/KingbaseESSelectTest.cs index fed8ea69..0e0d8697 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/KingbaseES/Curd/KingbaseESSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/KingbaseES/Curd/KingbaseESSelectTest.cs @@ -1680,7 +1680,7 @@ WHERE ((((a.""ID"")::varchar) in (SELECT b.""TITLE"" new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1718,6 +1718,28 @@ WHERE ((((a.""ID"")::varchar) in (SELECT b.""TITLE"" Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(4, t3.Count); + Assert.Equal("100000", t3[0].Code); + Assert.Equal("110000", t3[1].Code); + Assert.Equal("110100", t3[2].Code); + Assert.Equal("110101", t3[3].Code); + + t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(3, t3.Count); + Assert.Equal("110000", t3[0].Code); + Assert.Equal("110100", t3[1].Code); + Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/MySql/Curd/MySqlSelectTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/MySql/Curd/MySqlSelectTest.cs index fc1cd64f..546a0e06 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/MySql/Curd/MySqlSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/MySql/Curd/MySqlSelectTest.cs @@ -1876,7 +1876,7 @@ WHERE ((b.`IsFinished` OR a.`TaskType` = 3) AND b.`EnabledMark` = 1)", groupsql1 new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1914,6 +1914,28 @@ WHERE ((b.`IsFinished` OR a.`TaskType` = 3) AND b.`EnabledMark` = 1)", groupsql1 Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + //t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + //Assert.Single(t3); + //Assert.Equal("100000", t3[0].Code); + //Assert.Single(t3[0].Childs); + //Assert.Equal("110000", t3[0].Childs[0].Code); + //Assert.Equal(2, t3[0].Childs[0].Childs.Count); + //Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + //Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + //t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + //Assert.Equal(4, t3.Count); + //Assert.Equal("100000", t3[0].Code); + //Assert.Equal("110000", t3[1].Code); + //Assert.Equal("110100", t3[2].Code); + //Assert.Equal("110101", t3[3].Code); + + //t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + //Assert.Equal(3, t3.Count); + //Assert.Equal("110000", t3[0].Code); + //Assert.Equal("110100", t3[1].Code); + //Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Oracle/Curd/OracleSelectTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Oracle/Curd/OracleSelectTest.cs index fa4e36d9..8b849b1a 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Oracle/Curd/OracleSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Oracle/Curd/OracleSelectTest.cs @@ -1716,7 +1716,7 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE"" new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1754,6 +1754,28 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE"" Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(4, t3.Count); + Assert.Equal("100000", t3[0].Code); + Assert.Equal("110000", t3[1].Code); + Assert.Equal("110100", t3[2].Code); + Assert.Equal("110101", t3[3].Code); + + t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(3, t3.Count); + Assert.Equal("110000", t3[0].Code); + Assert.Equal("110100", t3[1].Code); + Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/PostgreSQL/Curd/PostgreSQLSelectTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/PostgreSQL/Curd/PostgreSQLSelectTest.cs index f0e048a1..96cec0f8 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/PostgreSQL/Curd/PostgreSQLSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/PostgreSQL/Curd/PostgreSQLSelectTest.cs @@ -1775,7 +1775,7 @@ WHERE ((((a.""id"")::varchar) in (SELECT b.""title"" new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1813,6 +1813,28 @@ WHERE ((((a.""id"")::varchar) in (SELECT b.""title"" Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(4, t3.Count); + Assert.Equal("100000", t3[0].Code); + Assert.Equal("110000", t3[1].Code); + Assert.Equal("110100", t3[2].Code); + Assert.Equal("110101", t3[3].Code); + + t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(3, t3.Count); + Assert.Equal("110000", t3[0].Code); + Assert.Equal("110100", t3[1].Code); + Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/SqlServer/Curd/SqlServerSelectTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/SqlServer/Curd/SqlServerSelectTest.cs index ffd98967..92b4fe3f 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/SqlServer/Curd/SqlServerSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/SqlServer/Curd/SqlServerSelectTest.cs @@ -1666,7 +1666,7 @@ WHERE (((cast(a.[Id] as nvarchar(100))) in (SELECT b.[Title] new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1704,6 +1704,28 @@ WHERE (((cast(a.[Id] as nvarchar(100))) in (SELECT b.[Title] Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(4, t3.Count); + Assert.Equal("100000", t3[0].Code); + Assert.Equal("110000", t3[1].Code); + Assert.Equal("110100", t3[2].Code); + Assert.Equal("110101", t3[3].Code); + + t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(3, t3.Count); + Assert.Equal("110000", t3[0].Code); + Assert.Equal("110100", t3[1].Code); + Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests/Dameng/Curd/DamengSelectTest.cs b/FreeSql.Tests/FreeSql.Tests/Dameng/Curd/DamengSelectTest.cs index c19346f9..c6e2751f 100644 --- a/FreeSql.Tests/FreeSql.Tests/Dameng/Curd/DamengSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/Dameng/Curd/DamengSelectTest.cs @@ -1716,7 +1716,7 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE"" new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1754,6 +1754,28 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE"" Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(4, t3.Count); + Assert.Equal("100000", t3[0].Code); + Assert.Equal("110000", t3[1].Code); + Assert.Equal("110100", t3[2].Code); + Assert.Equal("110101", t3[3].Code); + + t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(3, t3.Count); + Assert.Equal("110000", t3[0].Code); + Assert.Equal("110100", t3[1].Code); + Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs b/FreeSql.Tests/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs index bfe8db80..d4166792 100644 --- a/FreeSql.Tests/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs @@ -1929,7 +1929,7 @@ WHERE ((b.`IsFinished` OR a.`TaskType` = 3) AND b.`EnabledMark` = 1)", groupsql1 new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1967,6 +1967,28 @@ WHERE ((b.`IsFinished` OR a.`TaskType` = 3) AND b.`EnabledMark` = 1)", groupsql1 Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + //t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + //Assert.Single(t3); + //Assert.Equal("100000", t3[0].Code); + //Assert.Single(t3[0].Childs); + //Assert.Equal("110000", t3[0].Childs[0].Code); + //Assert.Equal(2, t3[0].Childs[0].Childs.Count); + //Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + //Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + //t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + //Assert.Equal(4, t3.Count); + //Assert.Equal("100000", t3[0].Code); + //Assert.Equal("110000", t3[1].Code); + //Assert.Equal("110100", t3[2].Code); + //Assert.Equal("110101", t3[3].Code); + + //t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + //Assert.Equal(3, t3.Count); + //Assert.Equal("110000", t3[0].Code); + //Assert.Equal("110100", t3[1].Code); + //Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs b/FreeSql.Tests/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs index c61ce957..3a922613 100644 --- a/FreeSql.Tests/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs @@ -1716,7 +1716,7 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE"" new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1754,6 +1754,28 @@ WHERE (((to_char(a.""ID"")) in (SELECT b.""TITLE"" Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(4, t3.Count); + Assert.Equal("100000", t3[0].Code); + Assert.Equal("110000", t3[1].Code); + Assert.Equal("110100", t3[2].Code); + Assert.Equal("110101", t3[3].Code); + + t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(3, t3.Count); + Assert.Equal("110000", t3[0].Code); + Assert.Equal("110100", t3[1].Code); + Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs b/FreeSql.Tests/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs index db9854e2..4ce6ea32 100644 --- a/FreeSql.Tests/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs @@ -1791,7 +1791,7 @@ WHERE ((((a.""id"")::varchar) in (SELECT b.""title"" new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1829,6 +1829,28 @@ WHERE ((((a.""id"")::varchar) in (SELECT b.""title"" Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(4, t3.Count); + Assert.Equal("100000", t3[0].Code); + Assert.Equal("110000", t3[1].Code); + Assert.Equal("110100", t3[2].Code); + Assert.Equal("110101", t3[3].Code); + + t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(3, t3.Count); + Assert.Equal("110000", t3[0].Code); + Assert.Equal("110100", t3[1].Code); + Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs b/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs index dd8daa73..3efaedbf 100644 --- a/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs @@ -1747,7 +1747,7 @@ WHERE (((cast(a.[Id] as nvarchar(100))) in (SELECT b.[Title] new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1785,6 +1785,28 @@ WHERE (((cast(a.[Id] as nvarchar(100))) in (SELECT b.[Title] Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(4, t3.Count); + Assert.Equal("100000", t3[0].Code); + Assert.Equal("110000", t3[1].Code); + Assert.Equal("110100", t3[2].Code); + Assert.Equal("110101", t3[3].Code); + + t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(3, t3.Count); + Assert.Equal("110000", t3[0].Code); + Assert.Equal("110100", t3[1].Code); + Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs b/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs index f117bdd9..9631464f 100644 --- a/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs @@ -1865,7 +1865,7 @@ WHERE (((cast(a.""Id"" as character)) in (SELECT b.""Title"" new VM_District_Child { Code = "110000", - Name = "北京市", + Name = "北京", Childs = new List(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, @@ -1903,6 +1903,28 @@ WHERE (((cast(a.""Id"" as character)) in (SELECT b.""Title"" Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(4, t3.Count); + Assert.Equal("100000", t3[0].Code); + Assert.Equal("110000", t3[1].Code); + Assert.Equal("110100", t3[2].Code); + Assert.Equal("110101", t3[3].Code); + + t3 = fsql.Select().Where(a => a.Name == "北京").AsCteTree().OrderBy(a => a.Code).ToList(); + Assert.Equal(3, t3.Count); + Assert.Equal("110000", t3[0].Code); + Assert.Equal("110100", t3[1].Code); + Assert.Equal("110101", t3[2].Code); } [Table(Name = "D_District")] diff --git a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs index ab1b955e..9b16690d 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs @@ -385,4 +385,80 @@ public static partial class FreeSqlGlobalExtensions } #endif #endregion + + #region WhereTree(..) 递归查询 + /// + /// 使用递归 CTE 查询树型的所有子数据。 + /// 通过测试的数据库:MySql8.0、SqlServer、PostgreSQL、Oracle、Sqlite、达梦、人大金仓 + /// + /// + /// + /// 深度 + /// + public static ISelect AsCteTree(this ISelect that, int depth = -1) where T1 : class + { + var select = that as Select1Provider; + var tb = select._tables[0].Table; + var navs = tb.Properties.Select(a => tb.GetTableRef(a.Key, false)) + .Where(a => a != null && + a.RefType == FreeSql.Internal.Model.TableRefType.OneToMany && + a.RefEntityType == tb.Type).ToArray(); + + if (navs.Length != 1) throw new ArgumentException($"{tb.Type.FullName} 不是父子关系,无法使用该功能"); + var tbref = navs[0]; + + var cteName = "as_cte_tree"; + if (select._orm.CodeFirst.IsSyncStructureToLower) cteName = cteName.ToLower(); + if (select._orm.CodeFirst.IsSyncStructureToUpper) cteName = cteName.ToUpper(); + var sql1 = select.ToSql($"0 as as_cte_tree_depth, {select.GetAllFieldExpressionTreeLevel2().Field}").Trim(); + + select._where.Clear(); + select.As("wct2"); + var sql2Field = select.GetAllFieldExpressionTreeLevel2().Field; + var sql2 = select + .AsAlias((type, old) => type == tb.Type ? old.Replace("wct2", "wct1") : 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)}"))}") + .ToSql($"wct1.as_cte_tree_depth + 1 as as_cte_tree_depth, {sql2Field}").Trim(); + + var newSelect = select._orm.Select() + .AsType(tb.Type) + .AsTable((type, old) => type == tb.Type ? cteName : old) + .WhereIf(depth > 0, $"a.as_cte_tree_depth < {depth + 1}") as Select1Provider; + + var nsselsb = new StringBuilder(); + if (AdoProvider.IsFromSlave(select._select) == false) nsselsb.Append(" "); //读写分离规则,如果强制读主库,则在前面加个空格 + nsselsb.Append("WITH "); + switch (select._orm.Ado.DataType) + { + case DataType.PostgreSQL: + case DataType.OdbcPostgreSQL: + case DataType.OdbcKingbaseES: + case DataType.ShenTong: //神通测试未通过 + case DataType.MySql: + case DataType.OdbcMySql: + nsselsb.Append("RECURSIVE "); + break; + } + nsselsb.Append(select._commonUtils.QuoteSqlName(cteName)); + switch (select._orm.Ado.DataType) + { + case DataType.Oracle: //[Err] ORA-32039: recursive WITH clause must have column alias list + case DataType.OdbcOracle: + case DataType.Dameng: //递归 WITH 子句必须具有列别名列表 + case DataType.OdbcDameng: + nsselsb.Append($"(as_cte_tree_depth, {sql2Field.Replace("wct2.", "")})"); + break; + } + nsselsb.Append(@" +as +( +").Append(sql1).Append("\r\n\r\nunion all\r\n\r\n").Append(sql2).Append(@" +) +SELECT "); + newSelect._select = nsselsb.ToString(); + nsselsb.Clear(); + return newSelect; + } + #endregion } \ No newline at end of file diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 5d1ff11c..8738cbb9 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -3653,6 +3653,16 @@ + + + 使用递归 CTE 查询树型的所有子数据。 + 通过测试的数据库:MySql8.0、SqlServer、PostgreSQL、Oracle、Sqlite、达梦、人大金仓 + + + + 深度 + + 使用 and 拼接两个 lambda 表达式 diff --git a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs index 1d31f146..bde0e6e8 100644 --- a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs +++ b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs @@ -533,7 +533,7 @@ namespace FreeSql.Internal.CommonProvider if (transaction == null && connection == null) { //读写分离规则 - if (this.SlavePools.Any() && cmdText.StartsWith("SELECT ", StringComparison.CurrentCultureIgnoreCase)) + if (this.SlavePools.Any() && IsFromSlave(cmdText)) { var availables = slaveUnavailables == 0 ? //查从库 diff --git a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs index 356222af..f6784181 100644 --- a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs +++ b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs @@ -458,7 +458,7 @@ namespace FreeSql.Internal.CommonProvider if (transaction == null && connection == null) { //读写分离规则 - if (this.SlavePools.Any() && cmdText.StartsWith("SELECT ", StringComparison.CurrentCultureIgnoreCase)) + if (this.SlavePools.Any() && IsFromSlave(cmdText)) { var availables = slaveUnavailables == 0 ? //查从库 diff --git a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderUtils.cs b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderUtils.cs index a8b1d542..a5461a4d 100644 --- a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderUtils.cs +++ b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderUtils.cs @@ -45,5 +45,11 @@ namespace FreeSql.Internal.CommonProvider return sb.Length == 0 ? "(NULL)" : sb.Remove(0, 1).Insert(0, "(").Append(")").ToString(); } + + public static bool IsFromSlave(string cmdText) + { + return cmdText.StartsWith("SELECT ", StringComparison.CurrentCultureIgnoreCase) || + cmdText.StartsWith("WITH ", StringComparison.CurrentCultureIgnoreCase); + } } } diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs index 62b9784d..79fb1956 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs @@ -596,7 +596,7 @@ namespace FreeSql.Internal.CommonProvider public int FieldCount { get; set; } public Func Read { get; set; } } - protected GetAllFieldExpressionTreeInfo GetAllFieldExpressionTreeLevelAll() + public GetAllFieldExpressionTreeInfo GetAllFieldExpressionTreeLevelAll() { return _dicGetAllFieldExpressionTree.GetOrAdd($"*{string.Join("+", _tables.Select(a => $"{_orm.Ado.DataType}-{a.Table.DbName}-{a.Alias}-{a.Type}"))}", s => { @@ -735,7 +735,7 @@ namespace FreeSql.Internal.CommonProvider }; }); } - protected GetAllFieldExpressionTreeInfo GetAllFieldExpressionTreeLevel2() + public GetAllFieldExpressionTreeInfo GetAllFieldExpressionTreeLevel2() { return _dicGetAllFieldExpressionTree.GetOrAdd(string.Join("+", _tables.Select(a => $"{_orm.Ado.DataType}-{a.Table.DbName}-{a.Alias}-{a.Type}")), s => {