diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml
index 2d6d3409..b54d4d0e 100644
--- a/FreeSql.DbContext/FreeSql.DbContext.xml
+++ b/FreeSql.DbContext/FreeSql.DbContext.xml
@@ -509,14 +509,5 @@
-
-
- 批量注入 Repository,可以参考代码自行调整
-
-
-
-
-
-
diff --git a/FreeSql.Tests/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs b/FreeSql.Tests/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs
index 2d0bacb3..3f9792de 100644
--- a/FreeSql.Tests/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs
+++ b/FreeSql.Tests/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs
@@ -1989,43 +1989,49 @@ WHERE ((b.`IsFinished` OR a.`TaskType` = 3) AND b.`EnabledMark` = 1)", groupsql1
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 == "中国").AsTreeCte().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 == "中国").AsTreeCte().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 == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
- //Assert.Equal(4, t3.Count);
- //Assert.Equal("100000", t3[0].Code);
- //Assert.Equal("110000", t3[1].Code);
- //Assert.Equal("110100", t3[2].Code);
- //Assert.Equal("110101", t3[3].Code);
+ t3 = fsql.Select().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList();
+ Assert.Equal(4, t3.Count);
+ Assert.Equal("100000", t3[0].Code);
+ Assert.Equal("110000", t3[1].Code);
+ Assert.Equal("110100", t3[2].Code);
+ Assert.Equal("110101", t3[3].Code);
- //t3 = fsql.Select().Where(a => a.Name == "北京").AsTreeCte().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);
+ t3 = fsql.Select().Where(a => a.Name == "北京").AsTreeCte().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);
- //var select = fsql.Select()
- // .Where(a => a.Name == "中国")
- // .AsTreeCte()
- // //.OrderBy("a.cte_level desc") //递归层级
- // ;
- //// var list = select.ToList(); //自己调试看查到的数据
- //select.ToUpdate().Set(a => a.testint, 855).ExecuteAffrows();
- //Assert.Equal(855, fsql.Select()
- // .Where(a => a.Name == "中国")
- // .AsTreeCte().Distinct().First(a => a.testint));
+ var t4 = fsql.Select().Where(a => a.Name == "东城区").AsTreeCte(up: true).ToList();
+ Assert.Equal(3, t4.Count);
+ Assert.Equal("110101", t4[0].Code);
+ Assert.Equal("110000", t4[1].Code);
+ Assert.Equal("100000", t4[2].Code);
- //Assert.Equal(4, select.ToDelete().ExecuteAffrows());
- //Assert.False(fsql.Select()
- // .Where(a => a.Name == "中国")
- // .AsTreeCte().Any());
+ var select = fsql.Select()
+ .Where(a => a.Name == "中国")
+ .AsTreeCte()
+ //.OrderBy("a.cte_level desc") //递归层级
+ ;
+ // var list = select.ToList(); //自己调试看查到的数据
+ select.ToUpdate().Set(a => a.testint, 855).ExecuteAffrows();
+ Assert.Equal(855, fsql.Select()
+ .Where(a => a.Name == "中国")
+ .AsTreeCte().Distinct().First(a => a.testint));
+
+ Assert.Equal(4, select.ToDelete().ExecuteAffrows());
+ Assert.False(fsql.Select()
+ .Where(a => a.Name == "中国")
+ .AsTreeCte().Any());
}
[Table(Name = "D_District")]
diff --git a/FreeSql.Tests/FreeSql.Tests/UnitTest4.cs b/FreeSql.Tests/FreeSql.Tests/UnitTest4.cs
index a6ff160e..84a3effb 100644
--- a/FreeSql.Tests/FreeSql.Tests/UnitTest4.cs
+++ b/FreeSql.Tests/FreeSql.Tests/UnitTest4.cs
@@ -30,7 +30,7 @@ namespace FreeSql.Tests
});
Assert.Equal(id, item2.xxx);
- fsql.Delete().Where("1=1").ExecuteAffrows();
+ fsql.Delete().Where("1=1").ExecuteAffrows();
fsql.Delete().Where("1=1").ExecuteAffrows();
var typeid = Guid.NewGuid();
fsql.Insert(new ts_iif_type { id = typeid, name = "type001" }).ExecuteAffrows();
diff --git a/FreeSql.Tests/FreeSql.Tests/g.cs b/FreeSql.Tests/FreeSql.Tests/g.cs
index 43f83258..a4f0f11d 100644
--- a/FreeSql.Tests/FreeSql.Tests/g.cs
+++ b/FreeSql.Tests/FreeSql.Tests/g.cs
@@ -9,7 +9,7 @@ public class g
{
static Lazy mysqlLazy = new Lazy(() => new FreeSql.FreeSqlBuilder()
- .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=5")
+ .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=5;Allow User Variables=True")
//.UseConnectionFactory(FreeSql.DataType.MySql, () => new MySql.Data.MySqlClient.MySqlConnection("Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;"))
//.UseConnectionString(FreeSql.DataType.MySql, "Data Source=192.168.164.10;Port=33061;User ID=root;Password=root;Initial Catalog=cccddd_mysqlconnector;Charset=utf8;SslMode=none;Max pool size=10")
.UseAutoSyncStructure(true)
diff --git a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs
index 67dbad00..531a8f8b 100644
--- a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs
+++ b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs
@@ -1,6 +1,7 @@
using FreeSql;
using FreeSql.DataAnnotations;
using FreeSql.Internal.CommonProvider;
+using FreeSql.Internal.ObjectPool;
using System;
using System.Collections;
using System.Collections.Concurrent;
@@ -378,10 +379,12 @@ public static partial class FreeSqlGlobalExtensions
#endregion
#region AsTreeCte(..) 递归查询
+ static ConcurrentDictionary _dicMySqlVersion = new ConcurrentDictionary();
///
/// 使用递归 CTE 查询树型的所有子记录,或者所有父记录。
/// 通过测试的数据库:MySql8.0、SqlServer、PostgreSQL、Oracle、Sqlite、Firebird、达梦、人大金仓、翰高
- /// 返回隐藏字段:.ToList(a => new { item = a, level = "a.cte_level", path = "a.cte_path" })
+ /// 返回隐藏字段:.ToList(a => new { item = a, level = "a.cte_level", path = "a.cte_path" })
+ /// * v2.0.0 兼容 MySql5.6 向上或向下查询,但不支持 pathSelector/pathSeparator 详细:https://github.com/dotnetcore/FreeSql/issues/536
///
///
///
@@ -409,6 +412,69 @@ public static partial class FreeSqlGlobalExtensions
var cteName = "as_tree_cte";
if (select._orm.CodeFirst.IsSyncStructureToLower) cteName = cteName.ToLower();
if (select._orm.CodeFirst.IsSyncStructureToUpper) cteName = cteName.ToUpper();
+
+ switch (select._orm.Ado.DataType) //MySql5.6
+ {
+ case DataType.MySql:
+ case DataType.OdbcMySql:
+ var mysqlConnectionString = select._orm.Ado?.ConnectionString ?? select._connection?.ConnectionString ?? "";
+ if (_dicMySqlVersion.TryGetValue(mysqlConnectionString, out var mysqlVersion) == false)
+ {
+ if (select._orm.Ado?.ConnectionString != null)
+ {
+ using (var mysqlconn = select._orm.Ado.MasterPool.Get())
+ mysqlVersion = mysqlconn.Value.ServerVersion;
+ }
+ else if (select._connection != null)
+ {
+ var isclosed = select._connection.State != ConnectionState.Open;
+ if (isclosed) select._connection.Open();
+ mysqlVersion = select._connection.ServerVersion;
+ if (isclosed) select._connection.Close();
+ }
+ }
+ if (int.TryParse((mysqlVersion ?? "").Split('.')[0], out var mysqlVersionFirst) && mysqlVersionFirst < 8)
+ {
+ if (tbref.Columns.Count > 1) throw new ArgumentException($"{tb.Type.FullName} 是父子关系,但是 MySql 8.0 以下版本中不支持组合多主键");
+ var mysql56Sql = "";
+ if (up == false)
+ {
+ mysql56Sql = $@"SELECT cte_tbc.cte_level, {select.GetAllFieldExpressionTreeLevel2().Field}
+ FROM (
+ SELECT @cte_ids as cte_ids, (
+ SELECT @cte_ids := group_concat({select._commonUtils.QuoteSqlName(tbref.Columns[0].Attribute.Name)})
+ FROM {select._commonUtils.QuoteSqlName(tb.DbName)}
+ WHERE find_in_set({select._commonUtils.QuoteSqlName(tbref.RefColumns[0].Attribute.Name)}, @cte_ids)
+ ) as cte_cids, @cte_level := @cte_idcte_levels + 1 as cte_level
+ FROM {select._commonUtils.QuoteSqlName(tb.DbName)}, (
+ SELECT @cte_ids := a.{select._commonUtils.QuoteSqlName(tbref.Columns[0].Attribute.Name)}, @cte_idcte_levels := 0
+ FROM {select._commonUtils.QuoteSqlName(tb.DbName)} a
+ WHERE 1=1{select._where}
+ LIMIT 1) cte_tbb
+ WHERE @cte_ids IS NOT NULL
+ ) cte_tbc, {select._commonUtils.QuoteSqlName(tb.DbName)} a
+ WHERE find_in_set(a.{select._commonUtils.QuoteSqlName(tbref.Columns[0].Attribute.Name)}, cte_tbc.cte_ids)";
+ select.WithSql(mysql56Sql).OrderBy("a.cte_level DESC");
+ select._where.Clear();
+ return select;
+ }
+ mysql56Sql = $@"SELECT cte_tbc.cte_level, {select.GetAllFieldExpressionTreeLevel2().Field}
+FROM (
+ SELECT @cte_pid as cte_id, (SELECT @cte_pid := {select._commonUtils.QuoteSqlName(tbref.RefColumns[0].Attribute.Name)} FROM {select._commonUtils.QuoteSqlName(tb.DbName)} WHERE {select._commonUtils.QuoteSqlName(tbref.Columns[0].Attribute.Name)} = cte_id) as cte_pid, @cte_level := @cte_level + 1 as cte_level
+ FROM {select._commonUtils.QuoteSqlName(tb.DbName)}, (
+ SELECT @cte_pid := a.{select._commonUtils.QuoteSqlName(tbref.Columns[0].Attribute.Name)}, @cte_level := 0
+ FROM {select._commonUtils.QuoteSqlName(tb.DbName)} a
+ WHERE 1=1{select._where}
+ LIMIT 1) cte_tbb
+) cte_tbc
+JOIN {select._commonUtils.QuoteSqlName(tb.DbName)} a ON cte_tbc.cte_id = a.{select._commonUtils.QuoteSqlName(tbref.Columns[0].Attribute.Name)}";
+ select.WithSql(mysql56Sql).OrderBy("a.cte_level");
+ select._where.Clear();
+ return select;
+ }
+ break;
+ }
+
var sql1ctePath = "";
if (pathSelector != null)
{
diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml
index b25afc15..3632c4f9 100644
--- a/FreeSql/FreeSql.xml
+++ b/FreeSql/FreeSql.xml
@@ -4369,7 +4369,8 @@
使用递归 CTE 查询树型的所有子记录,或者所有父记录。
通过测试的数据库:MySql8.0、SqlServer、PostgreSQL、Oracle、Sqlite、Firebird、达梦、人大金仓、翰高
- 返回隐藏字段:.ToList(a => new { item = a, level = "a.cte_level", path = "a.cte_path" })
+ 返回隐藏字段:.ToList(a => new { item = a, level = "a.cte_level", path = "a.cte_path" })
+ * v2.0.0 兼容 MySql5.6 向上或向下查询,但不支持 pathSelector/pathSeparator 详细:https://github.com/dotnetcore/FreeSql/issues/536