From 7ac0d62ed7d5f0d7be21b5db5a25e17a3ccb0be5 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Wed, 15 May 2019 19:08:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20IncludeMany=20=E5=8F=98?= =?UTF-8?q?=E5=BC=82=E5=A4=9A=E7=BA=A7=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs | 39 ++++++++++++++ FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs | 39 ++++++++++++++ .../PostgreSQL/Curd/PostgreSQLSelectTest.cs | 39 ++++++++++++++ .../SqlServer/Curd/SqlServerSelectTest.cs | 39 ++++++++++++++ FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs | 31 ++++++++--- FreeSql/FreeSql.csproj | 2 +- .../SelectProvider/Select1Provider.cs | 53 +++++++++++++------ 7 files changed, 218 insertions(+), 24 deletions(-) diff --git a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs index 32b237ef..cbe5383c 100644 --- a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs +++ b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs @@ -901,9 +901,48 @@ namespace FreeSql.Tests.MySql { Assert.Equal("SELECT a.`Id`, a.`Clicks`, a.`TypeGuid`, a.`Title`, a.`CreateTime` FROM `tb_topicAsTable1` a LEFT JOIN TestTypeInfo b on b.Guid = a.TypeGuid and b.Name = ?bname", sql); } + public class TestInclude_OneToManyModel1 { + [Column(IsIdentity = true)] + public int id { get; set; } + public virtual TestInclude_OneToManyModel2 model2 { get; set; } + + public string m1name { get; set; } + } + public class TestInclude_OneToManyModel2 { + [Column(IsPrimary = true)] + public int model2id { get; set; } + public virtual TestInclude_OneToManyModel1 model1 { get; set; } + + public string m2setting { get; set; } + + public List childs { get; set; } + } + public class TestInclude_OneToManyModel3 { + [Column(IsIdentity = true)] + public int id { get; set; } + + public int model2111Idaaa { get; set; } + public string title { get; set; } + } + [Fact] public void Include_OneToMany() { + var model1 = new TestInclude_OneToManyModel1 { m1name = DateTime.Now.Second.ToString() }; + model1.id = (int)g.mysql.Insert(model1).ExecuteIdentity(); + var model2 = new TestInclude_OneToManyModel2 { model2id = model1.id, m2setting = DateTime.Now.Second.ToString() }; + g.mysql.Insert(model2).ExecuteAffrows(); + var model3s = new[] { + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__111" }, + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__222" }, + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__333" } + }; + Assert.Equal(3, g.mysql.Insert(model3s).ExecuteAffrows()); + + var t1 = g.mysql.Select() + .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2111Idaaa == a.model2.model2id)) + .Where(a => a.id <= model1.id) + .ToList(); } [Fact] public void Include_OneToChilds() { diff --git a/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs b/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs index 3f942d32..8879cb26 100644 --- a/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs +++ b/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs @@ -794,9 +794,48 @@ namespace FreeSql.Tests.Oracle { Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22AsTable1\" a LEFT JOIN \"TESTTYPEINFO\" b on b.\"GUID\" = a.\"TYPEGUID\" and b.\"NAME\" = :bname", sql); } + public class TiOtmModel1 { + [Column(IsIdentity = true)] + public int id { get; set; } + public virtual TiOtmModel2 model2 { get; set; } + + public string m1name { get; set; } + } + public class TiOtmModel2 { + [Column(IsPrimary = true)] + public int model2id { get; set; } + public virtual TiOtmModel1 model1 { get; set; } + + public string m2setting { get; set; } + + public List childs { get; set; } + } + public class TiOtmModel3 { + [Column(IsIdentity = true)] + public int id { get; set; } + + public int model2111Idaaa { get; set; } + public string title { get; set; } + } + [Fact] public void Include_OneToMany() { + var model1 = new TiOtmModel1 { m1name = DateTime.Now.Second.ToString() }; + model1.id = (int)g.oracle.Insert(model1).ExecuteIdentity(); + var model2 = new TiOtmModel2 { model2id = model1.id, m2setting = DateTime.Now.Second.ToString() }; + g.oracle.Insert(model2).ExecuteAffrows(); + var model3s = new[] { + new TiOtmModel3{ model2111Idaaa = model1.id, title = "testmodel3__111" }, + new TiOtmModel3{ model2111Idaaa = model1.id, title = "testmodel3__222" }, + new TiOtmModel3{ model2111Idaaa = model1.id, title = "testmodel3__333" } + }; + Assert.Equal(3, g.oracle.Insert(model3s).ExecuteAffrows()); + + var t1 = g.oracle.Select() + .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2111Idaaa == a.model2.model2id)) + .Where(a => a.id <= model1.id) + .ToList(); } [Fact] public void Include_OneToChilds() { diff --git a/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs b/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs index e8c39652..41249f7b 100644 --- a/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs +++ b/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs @@ -860,9 +860,48 @@ namespace FreeSql.Tests.PostgreSQL { Assert.Equal("SELECT a.\"id\", a.\"clicks\", a.\"typeguid\", a.\"title\", a.\"createtime\" FROM \"tb_topicAsTable1\" a LEFT JOIN \"testtypeinfo\" b on b.\"guid\" = a.\"typeguid\" and b.\"name\" = @bname", sql); } + public class TestInclude_OneToManyModel1 { + [Column(IsIdentity = true)] + public int id { get; set; } + public virtual TestInclude_OneToManyModel2 model2 { get; set; } + + public string m1name { get; set; } + } + public class TestInclude_OneToManyModel2 { + [Column(IsPrimary = true)] + public int model2id { get; set; } + public virtual TestInclude_OneToManyModel1 model1 { get; set; } + + public string m2setting { get; set; } + + public List childs { get; set; } + } + public class TestInclude_OneToManyModel3 { + [Column(IsIdentity = true)] + public int id { get; set; } + + public int model2111Idaaa { get; set; } + public string title { get; set; } + } + [Fact] public void Include_OneToMany() { + var model1 = new TestInclude_OneToManyModel1 { m1name = DateTime.Now.Second.ToString() }; + model1.id = (int)g.pgsql.Insert(model1).ExecuteIdentity(); + var model2 = new TestInclude_OneToManyModel2 { model2id = model1.id, m2setting = DateTime.Now.Second.ToString() }; + g.pgsql.Insert(model2).ExecuteAffrows(); + var model3s = new[] { + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__111" }, + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__222" }, + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__333" } + }; + Assert.Equal(3, g.pgsql.Insert(model3s).ExecuteAffrows()); + + var t1 = g.pgsql.Select() + .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2111Idaaa == a.model2.model2id)) + .Where(a => a.id <= model1.id) + .ToList(); } [Fact] public void Include_OneToChilds() { diff --git a/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs b/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs index 3f34a318..6aadf12b 100644 --- a/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs +++ b/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs @@ -791,9 +791,48 @@ namespace FreeSql.Tests.SqlServer { Assert.Equal("SELECT a.[Id], a.[Clicks], a.[TypeGuid], a.[Title], a.[CreateTime] FROM [tb_topic22AsTable1] a LEFT JOIN TestTypeInfo b on b.Guid = a.TypeGuid and b.Name = @bname", sql); } + public class TestInclude_OneToManyModel1 { + [Column(IsIdentity = true)] + public int id { get; set; } + public virtual TestInclude_OneToManyModel2 model2 { get; set; } + + public string m1name { get; set; } + } + public class TestInclude_OneToManyModel2 { + [Column(IsPrimary = true)] + public int model2id { get; set; } + public virtual TestInclude_OneToManyModel1 model1 { get; set; } + + public string m2setting { get; set; } + + public List childs { get; set; } + } + public class TestInclude_OneToManyModel3 { + [Column(IsIdentity = true)] + public int id { get; set; } + + public int model2111Idaaa { get; set; } + public string title { get; set; } + } + [Fact] public void Include_OneToMany() { + var model1 = new TestInclude_OneToManyModel1 { m1name = DateTime.Now.Second.ToString() }; + model1.id = (int)_sqlserverFixture.SqlServer.Insert(model1).ExecuteIdentity(); + var model2 = new TestInclude_OneToManyModel2 { model2id = model1.id, m2setting = DateTime.Now.Second.ToString() }; + _sqlserverFixture.SqlServer.Insert(model2).ExecuteAffrows(); + var model3s = new[] { + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__111" }, + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__222" }, + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__333" } + }; + Assert.Equal(3, _sqlserverFixture.SqlServer.Insert(model3s).ExecuteAffrows()); + + var t1 = _sqlserverFixture.SqlServer.Select() + .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2111Idaaa == a.model2.model2id)) + .Where(a => a.id <= model1.id) + .ToList(); } [Fact] public void Include_OneToChilds() { diff --git a/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs b/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs index 2764225a..106561f6 100644 --- a/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs +++ b/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs @@ -757,29 +757,48 @@ namespace FreeSql.Tests.Sqlite { Assert.Equal("SELECT a.\"Id\", a.\"Clicks\", a.\"TypeGuid\", a.\"Title\", a.\"CreateTime\" FROM \"tb_topic22AsTable1\" a LEFT JOIN \"TestTypeInfo\" b on b.\"Guid\" = a.\"TypeGuid\" and b.\"Name\" = @bname", sql); } - class TestInclude_OneToManyModel1 { + public class TestInclude_OneToManyModel1 { [Column(IsIdentity = true)] public int id { get; set; } public virtual TestInclude_OneToManyModel2 model2 { get; set; } + + public string m1name { get; set; } } - class TestInclude_OneToManyModel2 { + public class TestInclude_OneToManyModel2 { [Column(IsPrimary = true)] public int model2id { get; set; } - public virtual TestInclude_OneToManyModel2 model1 { get; set; } + public virtual TestInclude_OneToManyModel1 model1 { get; set; } - public virtual List childs { get; set; } + public string m2setting { get; set; } + + public List childs { get; set; } } - class TestInclude_OneToManyModel3 { + public class TestInclude_OneToManyModel3 { [Column(IsIdentity = true)] public int id { get; set; } + public int model2111Idaaa { get; set; } public string title { get; set; } } [Fact] public void Include_OneToMany() { - var model1 = new TestInclude_OneToManyModel1 { }; + var model1 = new TestInclude_OneToManyModel1 { m1name = DateTime.Now.Second.ToString() }; model1.id = (int)g.sqlite.Insert(model1).ExecuteIdentity(); + var model2 = new TestInclude_OneToManyModel2 { model2id = model1.id, m2setting = DateTime.Now.Second.ToString() }; + g.sqlite.Insert(model2).ExecuteAffrows(); + + var model3s = new [] { + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__111" }, + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__222" }, + new TestInclude_OneToManyModel3{ model2111Idaaa = model1.id, title = "testmodel3__333" } + }; + Assert.Equal(3, g.sqlite.Insert(model3s).ExecuteAffrows()); + + var t1 = g.sqlite.Select() + .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2111Idaaa == a.model2.model2id && m3.title == a.model2.m2setting)) + .Where(a => a.id <= model1.id) + .ToList(); } [Fact] public void Include_OneToChilds() { diff --git a/FreeSql/FreeSql.csproj b/FreeSql/FreeSql.csproj index ffbb4a96..4e9bb55b 100644 --- a/FreeSql/FreeSql.csproj +++ b/FreeSql/FreeSql.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 0.5.17 + 0.5.18 true YeXiangQin FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite. diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs index 72f7aa00..452d6e48 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs @@ -467,20 +467,39 @@ namespace FreeSql.Internal.CommonProvider { subSelect.Where(Expression.Lambda>( Expression.Call(null, containsMethod, arrExp, refCol), otmExpParm1)); } else { - var otmExpParm1 = Expression.Parameter(typeof(TNavigate), "a"); - Expression expOr = null; - foreach (var item in list) { - Expression expAnd = null; + var subSelectT1Alias = (subSelect as Select1Provider)._tables[0].Alias; + Dictionary sbDic = new Dictionary(); + for (var y = 0; y < list.Count; y++) { + var sbWhereOne = new StringBuilder(); + sbWhereOne.Append("("); for (var z = 0; z < tbref.Columns.Count; z++) { - var colVal = getListValue(item, tbref.Columns[z].CsName); - var expTmp = Expression.Equal(Expression.MakeMemberAccess(otmExpParm1, tbref2.Properties[tbref.RefColumns[0].CsName]), Expression.Constant(colVal)); - if (z == 0) expAnd = expTmp; - else expAnd = Expression.AndAlso(expAnd, expTmp); + if (z > 0) sbWhereOne.Append(" AND "); + sbWhereOne.Append(_commonUtils.FormatSql($"{subSelectT1Alias}.{_commonUtils.QuoteSqlName(tbref.RefColumns[z].Attribute.Name)}={{0}}", getListValue(list[y], tbref.Columns[z].CsName))); } - if (expOr == null) expOr = expAnd; - else expOr = Expression.OrElse(expOr, expAnd); + sbWhereOne.Append(")"); + var whereOne = sbWhereOne.ToString(); + sbWhereOne.Clear(); + if (sbDic.ContainsKey(whereOne) == false) sbDic.Add(whereOne, true); } - subSelect.Where(Expression.Lambda>(expOr, otmExpParm1)); + var sbWhere = new StringBuilder(); + foreach (var sbd in sbDic) + sbWhere.Append(" OR ").Append(sbd.Key); + subSelect.Where(sbWhere.Remove(0, 4).ToString()); + sbWhere.Clear(); + //var otmExpParm1 = Expression.Parameter(typeof(TNavigate), "a"); + //Expression expOr = null; + //foreach (var item in list) { + // Expression expAnd = null; + // for (var z = 0; z < tbref.Columns.Count; z++) { + // var colVal = getListValue(item, tbref.Columns[z].CsName); + // var expTmp = Expression.Equal(Expression.MakeMemberAccess(otmExpParm1, tbref2.Properties[tbref.RefColumns[z].CsName]), Expression.Constant(colVal)); + // if (z == 0) expAnd = expTmp; + // else expAnd = Expression.AndAlso(expAnd, expTmp); + // } + // if (expOr == null) expOr = expAnd; + // else expOr = Expression.OrElse(expOr, expAnd); + //} + //subSelect.Where(Expression.Lambda>(expOr, otmExpParm1)); } then?.Invoke(subSelect); var subList = subSelect.ToList(true); @@ -543,10 +562,10 @@ namespace FreeSql.Internal.CommonProvider { if (true) { var tbref2 = _commonUtils.GetTableByEntity(tbref.RefEntityType); var tbrefMid = _commonUtils.GetTableByEntity(tbref.RefMiddleEntityType); - var sbJoin = new StringBuilder().Append($"{_commonUtils.QuoteSqlName(tbrefMid.DbName)} midtb ON"); + var sbJoin = new StringBuilder().Append($"{_commonUtils.QuoteSqlName(tbrefMid.DbName)} midtb ON "); for (var z = 0; z < tbref.RefColumns.Count; z++) { - if (z > 0) sbJoin.Append(" AND"); - sbJoin.Append($" midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[tbref.Columns.Count + z].Attribute.Name)} = a.{_commonUtils.QuoteSqlName(tbref.RefColumns[z].Attribute.Name)}"); + if (z > 0) sbJoin.Append(" AND "); + sbJoin.Append($"midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[tbref.Columns.Count + z].Attribute.Name)} = a.{_commonUtils.QuoteSqlName(tbref.RefColumns[z].Attribute.Name)}"); } subSelect.InnerJoin(sbJoin.ToString()); sbJoin.Clear(); @@ -556,9 +575,9 @@ namespace FreeSql.Internal.CommonProvider { Dictionary sbDic = new Dictionary(); for (var y = 0; y < list.Count; y++) { var sbWhereOne = new StringBuilder(); - sbWhereOne.Append(" ("); + sbWhereOne.Append("("); for (var z = 0; z < tbref.Columns.Count; z++) { - if (z > 0) sbWhereOne.Append(" AND"); + if (z > 0) sbWhereOne.Append(" AND "); sbWhereOne.Append(_commonUtils.FormatSql($" midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[z].Attribute.Name)}={{0}}", getListValue(list[y], tbref.Columns[z].CsName))); } sbWhereOne.Append(")"); @@ -568,7 +587,7 @@ namespace FreeSql.Internal.CommonProvider { } var sbWhere = new StringBuilder(); foreach (var sbd in sbDic) - sbWhere.Append(" OR").Append(sbd.Key); + sbWhere.Append(" OR ").Append(sbd.Key); subSelect.Where(sbWhere.Remove(0, 3).ToString()); sbWhere.Clear(); }