From b62afec7bb170b7b5a0aa054d62a0d8252baaa3f Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Mon, 15 Jul 2019 18:10:59 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E8=A1=A5=E5=85=85=20Navigate(ManyToMany=20?= =?UTF-8?q?=3D=20typeof(=E4=B8=AD=E9=97=B4=E8=A1=A8))=20=E5=A4=9A=E5=AF=B9?= =?UTF-8?q?=E5=A4=9A=E8=87=AA=E5=AE=9A=E4=B9=89=E9=85=8D=E7=BD=AE=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FreeSql.Extensions.LazyLoading.csproj | 2 +- FreeSql.DbContext/FreeSql.DbContext.csproj | 2 +- FreeSql.Repository/FreeSql.Repository.csproj | 2 +- .../Navigate/ManyToManyTest.cs | 252 ++++++++++++ .../DataAnnotations/Navigate/ManyToOneTest.cs | 141 +++++++ .../DataAnnotations/Navigate/OneToManyTest.cs | 138 +++++++ .../DataAnnotations/Navigate/OneToOneTest.cs | 60 +++ FreeSql/DataAnnotations/NavigateAttribute.cs | 9 +- FreeSql/FreeSql.csproj | 2 +- FreeSql/FreeSql.xml | 7 +- .../SelectProvider/Select1Provider.cs | 2 - FreeSql/Internal/UtilsExpressionTree.cs | 376 +++++++++++------- .../FreeSql.Provider.MySql.csproj | 2 +- .../FreeSql.Provider.MySqlConnector.csproj | 2 +- .../FreeSql.Provider.Oracle.csproj | 2 +- .../FreeSql.Provider.PostgreSQL.csproj | 2 +- .../FreeSql.Provider.SqlServer.csproj | 2 +- .../FreeSql.Provider.Sqlite.csproj | 2 +- 18 files changed, 841 insertions(+), 164 deletions(-) create mode 100644 FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/ManyToManyTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/ManyToOneTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/OneToManyTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/OneToOneTest.cs diff --git a/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj b/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj index f030d113..b5919bdc 100644 --- a/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj +++ b/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.7.8 + 0.7.9 true YeXiangQin FreeSql 扩展包,可实现【延时加载】属性. diff --git a/FreeSql.DbContext/FreeSql.DbContext.csproj b/FreeSql.DbContext/FreeSql.DbContext.csproj index 98c92e77..249cb8ff 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.csproj +++ b/FreeSql.DbContext/FreeSql.DbContext.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.7.8 + 0.7.9 true YeXiangQin FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite. diff --git a/FreeSql.Repository/FreeSql.Repository.csproj b/FreeSql.Repository/FreeSql.Repository.csproj index c7ec9b73..11d8c3c7 100644 --- a/FreeSql.Repository/FreeSql.Repository.csproj +++ b/FreeSql.Repository/FreeSql.Repository.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.7.8 + 0.7.9 YeXiangQin FreeSql Implementation of General Repository, Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite, and read/write separation、and split table. https://github.com/2881099/FreeSql/wiki/Repository diff --git a/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/ManyToManyTest.cs b/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/ManyToManyTest.cs new file mode 100644 index 00000000..6d55f1c0 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/ManyToManyTest.cs @@ -0,0 +1,252 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Threading; +using Xunit; + +namespace FreeSql.Tests.DataAnnotations +{ + public class ManyToManyTest + { + Random rnd = new Random(); + + #region ԼԶ + [Fact] + public void Select() + { + var users = new mtm_user[10]; + var roles = new mtm_role[10]; + var urs = new List(); + for (var a = 0; a < users.Length; a++) + { + var uid = Guid.NewGuid(); + users[a] = new mtm_user + { + id = uid, + username = "û" + a + "_" + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + } + g.sqlite.Insert(users).ExecuteAffrows(); + for (var a = 0; a < roles.Length; a++) + { + var uid = Guid.NewGuid(); + roles[a] = new mtm_role + { + id = uid, + name = "ɫ" + a + "_" + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + } + g.sqlite.Insert(roles).ExecuteAffrows(); + + for (var a = 0; a < users.Length; a++) + { + for (var b = roles.Length; b >= 0; b--) + { + var ur = new mtm_user_mtm_role + { + mtm_user_id = users[a].id, + mtm_role_id = roles[rnd.Next(roles.Length)].id + }; + if (urs.Where(c => c.mtm_role_id == ur.mtm_role_id && c.mtm_user_id == ur.mtm_user_id).Any() == false) + urs.Add(ur); + } + } + g.sqlite.Insert(urs.ToArray()).ExecuteAffrows(); + + var select1 = g.sqlite.Select().Limit(10).OrderByDescending(a => a.createtime).ToList(true); + + var select2 = g.sqlite.Select().IncludeMany(a => a.mtm_roles).Limit(10).OrderByDescending(a => a.createtime).ToList(true); + } + + public class mtm_user + { + public Guid id { get; set; } + public string username { get; set; } + public DateTime createtime { get; set; } + + public virtual List mtm_roles { get; set; } + } + public class mtm_user_mtm_role + { + public Guid mtm_user_id { get; set; } + public Guid mtm_role_id { get; set; } + + public mtm_user mtm_user { get; set; } + public mtm_role mtm_role { get; set; } + } + public class mtm_role + { + public Guid id { get; set; } + + public string name { get; set; } + public DateTime createtime { get; set; } + + public virtual List mtm_users { get; set; } + } + #endregion + + #region ԶԶ࣬мΪԼ + [Fact] + public void Navigate1() + { + var users = new mtm_user_nav1[10]; + var roles = new mtm_role_nav1[10]; + var urs = new List(); + for (var a = 0; a < users.Length; a++) + { + var uid = Guid.NewGuid(); + users[a] = new mtm_user_nav1 + { + id = uid, + username = "û" + a + "_" + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + } + g.sqlite.Insert(users).ExecuteAffrows(); + for (var a = 0; a < roles.Length; a++) + { + var uid = Guid.NewGuid(); + roles[a] = new mtm_role_nav1 + { + id = uid, + name = "ɫ" + a + "_" + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + } + g.sqlite.Insert(roles).ExecuteAffrows(); + + for (var a = 0; a < users.Length; a++) + { + for (var b = roles.Length; b >= 0; b--) + { + var ur = new user_role_nav1 + { + user_id = users[a].id, + role_id = roles[rnd.Next(roles.Length)].id + }; + if (urs.Where(c => c.role_id == ur.role_id && c.user_id == ur.user_id).Any() == false) + urs.Add(ur); + } + } + g.sqlite.Insert(urs.ToArray()).ExecuteAffrows(); + + var select1 = g.sqlite.Select().Limit(10).OrderByDescending(a => a.createtime).ToList(true); + + var select2 = g.sqlite.Select().IncludeMany(a => a.roles).Limit(10).OrderByDescending(a => a.createtime).ToList(true); + } + + public class mtm_user_nav1 + { + public Guid id { get; set; } + public string username { get; set; } + public DateTime createtime { get; set; } + + [Navigate(ManyToMany = typeof(user_role_nav1))] + public virtual List roles { get; set; } + } + public class user_role_nav1 + { + public Guid user_id { get; set; } + public Guid role_id { get; set; } + + public mtm_user_nav1 user { get; set; } + public mtm_role_nav1 role { get; set; } + } + public class mtm_role_nav1 + { + public Guid id { get; set; } + + public string name { get; set; } + public DateTime createtime { get; set; } + + [Navigate(ManyToMany = typeof(user_role_nav1))] + public virtual List users { get; set; } + } + #endregion + + #region ԶԶ࣬мΪԶ + [Fact] + public void Navigate() + { + var users = new mtm_user_nav[10]; + var roles = new mtm_role_nav[10]; + var urs = new List(); + for (var a = 0; a < users.Length; a++) + { + var uid = Guid.NewGuid(); + users[a] = new mtm_user_nav + { + id = uid, + username = "û" + a + "_" + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + } + g.sqlite.Insert(users).ExecuteAffrows(); + for (var a = 0; a < roles.Length; a++) + { + var uid = Guid.NewGuid(); + roles[a] = new mtm_role_nav + { + id = uid, + name = "ɫ" + a + "_" + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + } + g.sqlite.Insert(roles).ExecuteAffrows(); + + for (var a = 0; a < users.Length; a++) + { + for (var b = roles.Length; b >= 0; b--) + { + var ur = new user_role_nav + { + user_pkid = users[a].id, + role_pkid = roles[rnd.Next(roles.Length)].id + }; + if (urs.Where(c => c.role_pkid == ur.role_pkid && c.user_pkid == ur.user_pkid).Any() == false) + urs.Add(ur); + } + } + g.sqlite.Insert(urs.ToArray()).ExecuteAffrows(); + + var select1 = g.sqlite.Select().Limit(10).OrderByDescending(a => a.createtime).ToList(true); + + var select2 = g.sqlite.Select().IncludeMany(a => a.roles).Limit(10).OrderByDescending(a => a.createtime).ToList(true); + } + + public class mtm_user_nav + { + public Guid id { get; set; } + public string username { get; set; } + public DateTime createtime { get; set; } + + [Navigate(ManyToMany = typeof(user_role_nav))] + public virtual List roles { get; set; } + } + public class user_role_nav + { + public Guid user_pkid { get; set; } + public Guid role_pkid { get; set; } + + [Navigate("user_pkid")] + public mtm_user_nav user { get; set; } + [Navigate("role_pkid")] + public mtm_role_nav role { get; set; } + } + public class mtm_role_nav + { + public Guid id { get; set; } + + public string name { get; set; } + public DateTime createtime { get; set; } + + [Navigate(ManyToMany = typeof(user_role_nav))] + public virtual List users { get; set; } + } + #endregion + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/ManyToOneTest.cs b/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/ManyToOneTest.cs new file mode 100644 index 00000000..dce116e9 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/ManyToOneTest.cs @@ -0,0 +1,141 @@ +using FreeSql.DataAnnotations; +using System; +using System.Numerics; +using Xunit; + +namespace FreeSql.Tests.DataAnnotations +{ + public class ManyToOneTest + { + #region Լһ + [Fact] + public void Select() + { + var users = new mto_user[10]; + var topics = new mto_topic[30]; + for (var a = 0; a < users.Length; a++) + { + var uid = Guid.NewGuid(); + users[a] = new mto_user + { + id = uid, + username = Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3] = new mto_topic + { + id = Guid.NewGuid(), + userid = uid, + title = "Ա" + (a * 3) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3 + 1] = new mto_topic + { + id = Guid.NewGuid(), + userid = uid, + title = "Ա" + (a * 3 + 1) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3 + 2] = new mto_topic + { + id = Guid.NewGuid(), + userid = uid, + title = "Ա" + (a * 3 + 2) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + } + g.sqlite.Insert(users).ExecuteAffrows(); + g.sqlite.Insert(topics).ExecuteAffrows(); + + var select1 = g.sqlite.Select().Limit(30).OrderByDescending(a => a.createtime).ToList(true); + + var select2 = g.sqlite.Select().Include(a => a.user).Limit(30).OrderByDescending(a => a.createtime).ToList(true); + + var firstct = users[0].createtime.AddSeconds(-1); + var select3 = g.sqlite.Select().Where(a => a.user.createtime > firstct).Limit(30).OrderByDescending(a => a.createtime).ToList(true); + } + + public class mto_user + { + public Guid id { get; set; } + public string username { get; set; } + public DateTime createtime { get; set; } + } + public class mto_topic + { + public Guid id { get; set; } + public Guid userid { get; set; } + public virtual mto_user user { get; set; } + + public string title { get; set; } + public DateTime createtime { get; set; } + } + #endregion + + #region Զһ + [Fact] + public void Navigate() + { + var users = new mto_user_nav[10]; + var topics = new mto_topic_nav[30]; + for (var a = 0; a < users.Length; a++) + { + var uid = Guid.NewGuid(); + users[a] = new mto_user_nav + { + id = uid, + username = Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3] = new mto_topic_nav + { + id = Guid.NewGuid(), + user_nav_pkid = uid, + title = "Ա" + (a * 3) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3 + 1] = new mto_topic_nav + { + id = Guid.NewGuid(), + user_nav_pkid = uid, + title = "Ա" + (a * 3 + 1) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3 + 2] = new mto_topic_nav + { + id = Guid.NewGuid(), + user_nav_pkid = uid, + title = "Ա" + (a * 3 + 2) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + } + g.sqlite.Insert(users).ExecuteAffrows(); + g.sqlite.Insert(topics).ExecuteAffrows(); + + var select1 = g.sqlite.Select().Limit(30).OrderByDescending(a => a.createtime).ToList(true); + + var select2 = g.sqlite.Select().Include(a => a.user).Limit(30).OrderByDescending(a => a.createtime).ToList(true); + + var firstct = users[0].createtime.AddSeconds(-1); + var select3 = g.sqlite.Select().Where(a => a.user.createtime > firstct).Limit(30).OrderByDescending(a => a.createtime).ToList(true); + } + + public class mto_user_nav + { + public Guid id { get; set; } + public string username { get; set; } + public DateTime createtime { get; set; } + } + public class mto_topic_nav + { + public Guid id { get; set; } + public Guid user_nav_pkid { get; set; } + [Navigate("user_nav_pkid")] + public virtual mto_user_nav user { get; set; } + + public string title { get; set; } + public DateTime createtime { get; set; } + } + #endregion + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/OneToManyTest.cs b/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/OneToManyTest.cs new file mode 100644 index 00000000..2597db78 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/OneToManyTest.cs @@ -0,0 +1,138 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Numerics; +using Xunit; + +namespace FreeSql.Tests.DataAnnotations +{ + public class OneToManyTest + { + #region ԼһԶ + [Fact] + public void Select() + { + var users = new mto_user[10]; + var topics = new mto_topic[30]; + for (var a = 0; a < users.Length; a++) + { + var uid = Guid.NewGuid(); + users[a] = new mto_user + { + id = uid, + username = Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3] = new mto_topic + { + id = Guid.NewGuid(), + mto_userid = uid, + title = "Ա" + (a * 3) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3 + 1] = new mto_topic + { + id = Guid.NewGuid(), + mto_userid = uid, + title = "Ա" + (a * 3 + 1) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3 + 2] = new mto_topic + { + id = Guid.NewGuid(), + mto_userid = uid, + title = "Ա" + (a * 3 + 2) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + } + g.sqlite.Insert(users).ExecuteAffrows(); + g.sqlite.Insert(topics).ExecuteAffrows(); + + var select1 = g.sqlite.Select().Limit(10).OrderByDescending(a => a.createtime).ToList(true); + + var select2 = g.sqlite.Select().IncludeMany(a => a.mto_topics).Limit(10).OrderByDescending(a => a.createtime).ToList(true); + } + + public class mto_user + { + public Guid id { get; set; } + public string username { get; set; } + public DateTime createtime { get; set; } + + public virtual List mto_topics { get; set; } + } + public class mto_topic + { + public Guid id { get; set; } + public Guid mto_userid { get; set; } + + public string title { get; set; } + public DateTime createtime { get; set; } + } + #endregion + + #region ԶһԶ + [Fact] + public void Navigate() + { + var users = new otm_user_nav[10]; + var topics = new otm_topic_nav[30]; + for (var a = 0; a < users.Length; a++) + { + var uid = Guid.NewGuid(); + users[a] = new otm_user_nav + { + id = uid, + username = Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3] = new otm_topic_nav + { + id = Guid.NewGuid(), + user_nav_pkid = uid, + title = "Ա" + (a * 3) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3 + 1] = new otm_topic_nav + { + id = Guid.NewGuid(), + user_nav_pkid = uid, + title = "Ա" + (a * 3 + 1) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + topics[a * 3 + 2] = new otm_topic_nav + { + id = Guid.NewGuid(), + user_nav_pkid = uid, + title = "Ա" + (a * 3 + 2) + Guid.NewGuid().ToString("N"), + createtime = DateTime.Now + }; + } + g.sqlite.Insert(users).ExecuteAffrows(); + g.sqlite.Insert(topics).ExecuteAffrows(); + + var select1 = g.sqlite.Select().Limit(10).OrderByDescending(a => a.createtime).ToList(true); + + var select2 = g.sqlite.Select().IncludeMany(a => a.topics).Limit(10).OrderByDescending(a => a.createtime).ToList(true); + } + + public class otm_user_nav + { + public Guid id { get; set; } + public string username { get; set; } + public DateTime createtime { get; set; } + + [Navigate("user_nav_pkid")] + public virtual List topics { get; set; } + } + public class otm_topic_nav + { + public Guid id { get; set; } + public Guid user_nav_pkid { get; set; } + + public string title { get; set; } + public DateTime createtime { get; set; } + } + #endregion + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/OneToOneTest.cs b/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/OneToOneTest.cs new file mode 100644 index 00000000..83b855b0 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/DataAnnotations/Navigate/OneToOneTest.cs @@ -0,0 +1,60 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Xunit; + +namespace FreeSql.Tests.DataAnnotations +{ + public class OneToOneTest + { + [Fact] + public void Select() + { + var users = new oto_user[10]; + for (var a = 0; a < users.Length; a++) + { + var uid = Guid.NewGuid(); + users[a] = new oto_user + { + id = uid, + username = Guid.NewGuid().ToString("N"), + createtime = DateTime.Now, + ext = new oto_user_field + { + userid = uid, + age = a, + createtime = DateTime.Now + } + }; + } + g.sqlite.Insert(users).ExecuteAffrows(); + g.sqlite.Insert(users.Select(a => a.ext).ToArray()).ExecuteAffrows(); + + var select1 = g.sqlite.Select().Include(a => a.ext).Limit(10).OrderByDescending(a => a.createtime).ToList(true); + + var select2 = g.sqlite.Select().Limit(10).OrderByDescending(a => a.createtime).ToList(true); + + var select3 = g.sqlite.Select().Include(a => a.user).Limit(10).OrderByDescending(a => a.createtime).ToList(true); + } + + public class oto_user + { + public Guid id { get; set; } + public string username { get; set; } + public DateTime createtime { get; set; } + public oto_user_field ext { get; set; } + } + public class oto_user_field + { + [Column(IsPrimary = true)] + public Guid userid { get; set; } + public virtual oto_user user { get; set; } + + public int age { get; set; } + public DateTime createtime { get; set; } + } + } + +} diff --git a/FreeSql/DataAnnotations/NavigateAttribute.cs b/FreeSql/DataAnnotations/NavigateAttribute.cs index d908a627..f17b4348 100644 --- a/FreeSql/DataAnnotations/NavigateAttribute.cs +++ b/FreeSql/DataAnnotations/NavigateAttribute.cs @@ -7,13 +7,20 @@ namespace FreeSql.DataAnnotations { /// - /// 导航属性,手工绑定 + /// 手工绑定 OneToMany、ManyToOne 导航关系 /// public string Bind { get; set; } + /// + /// 手工绑定 ManyToMany 导航关系 + /// + public Type ManyToMany { get; set; } public NavigateAttribute(string bind) { this.Bind = bind; } + public NavigateAttribute() + { + } } } diff --git a/FreeSql/FreeSql.csproj b/FreeSql/FreeSql.csproj index 01607391..cf80f4d7 100644 --- a/FreeSql/FreeSql.csproj +++ b/FreeSql/FreeSql.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.7.8 + 0.7.9 true YeXiangQin FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite. diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index b8babb01..6b0870ec 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -115,7 +115,12 @@ - 导航属性,手工绑定 + 手工绑定 OneToMany、ManyToOne 导航关系 + + + + + 手工绑定 ManyToMany 导航关系 diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs index aba152e5..49f0a87d 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs @@ -902,9 +902,7 @@ namespace FreeSql.Internal.CommonProvider { string key = null; if (tbref.Columns.Count == 1) - { key = _orm.GetEntityValueWithPropertyName(tbref.RefMiddleEntityType, midList[a], tbref.MiddleColumns[0].CsName).ToString(); - } else { var sb = new StringBuilder(); diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index 6fc8eb7a..473a82bb 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -208,28 +208,22 @@ namespace FreeSql.Internal { if (trytb.Columns.TryGetValue(dbident.Name, out var trycol) && trycol.Attribute.MapType == dbident.CsType || trytb.ColumnsByCs.TryGetValue(dbident.Name, out trycol) && trycol.Attribute.MapType == dbident.CsType) - { trycol.Attribute.IsIdentity = true; - } } foreach (var dbpk in dbtb.Primarys) { if (trytb.Columns.TryGetValue(dbpk.Name, out var trycol) && trycol.Attribute.MapType == dbpk.CsType || trytb.ColumnsByCs.TryGetValue(dbpk.Name, out trycol) && trycol.Attribute.MapType == dbpk.CsType) - { trycol.Attribute.IsPrimary = true; - } } foreach (var dbuk in dbtb.UniquesDict) { foreach (var dbcol in dbuk.Value) { if (trytb.Columns.TryGetValue(dbcol.Name, out var trycol) && trycol.Attribute.MapType == dbcol.CsType || - trytb.ColumnsByCs.TryGetValue(dbcol.Name, out trycol) && trycol.Attribute.MapType == dbcol.CsType) - { + trytb.ColumnsByCs.TryGetValue(dbcol.Name, out trycol) && trycol.Attribute.MapType == dbcol.CsType) if (trycol.Attribute._Uniques?.Contains(dbuk.Key) != true) trycol.Attribute.Unique += $"," + dbuk.Key; - } } } } @@ -272,7 +266,8 @@ namespace FreeSql.Internal $"{pnv.PropertyType.Namespace}.{pnv.PropertyType.Name.Remove(pnv.PropertyType.Name.IndexOf('`'))}<{string.Join(", ", pnv.PropertyType.GenericTypeArguments.Select(a => a.IsNested ? $"{a.DeclaringType.Namespace}.{a.DeclaringType.Name}.{a.Name}" : $"{a.Namespace}.{a.Name}"))}>" : (pnv.PropertyType.IsNested ? $"{pnv.PropertyType.DeclaringType.Namespace}.{pnv.PropertyType.DeclaringType.Name}.{pnv.PropertyType.Name}" : $"{pnv.PropertyType.Namespace}.{pnv.PropertyType.Name}"); - var pnvBind = pnv.GetCustomAttribute()?.Bind.Split(',').Select(a => a.Trim()).Where(a => !string.IsNullOrEmpty(a)).ToArray(); + var pnvAttr = pnv.GetCustomAttribute(); + var pnvBind = pnvAttr?.Bind?.Split(',').Select(a => a.Trim()).Where(a => !string.IsNullOrEmpty(a)).ToArray(); var nvref = new TableRef(); nvref.Property = pnv; @@ -294,11 +289,47 @@ namespace FreeSql.Internal var tbrefTypeName = tbref.Type.IsNested ? $"{tbref.Type.DeclaringType.Namespace}.{tbref.Type.DeclaringType.Name}.{tbref.Type.Name}" : $"{tbref.Type.Namespace}.{tbref.Type.Name}"; Type midType = null; - var isManyToMany = propElementType != trytb.Type && - pnv.Name.EndsWith($"{tbref.CsName}s") && - tbref.Properties.Where(z => (z.Value.PropertyType.GenericTypeArguments.FirstOrDefault() == trytb.Type || z.Value.PropertyType.GetElementType() == trytb.Type) && - z.Key.EndsWith($"{trytb.CsName}s", StringComparison.CurrentCultureIgnoreCase) && - typeof(IEnumerable).IsAssignableFrom(z.Value.PropertyType)).Any(); + var isManyToMany = false; + + Action valiManyToMany = () => + { + if (midType != null) + { + var midTypeProps = midType.GetProperties(); + var midTypePropsTrytb = midTypeProps.Where(a => a.PropertyType == trytb.Type).Count(); + var midTypePropsTbref = midTypeProps.Where(a => a.PropertyType == tbref.Type).Count(); + if (midTypePropsTrytb != 1 || midTypePropsTbref != 1) midType = null; + } + }; + + if (pnvAttr?.ManyToMany != null) + { + isManyToMany = propElementType != trytb.Type && + tbref.Properties.Where(z => (z.Value.PropertyType.GenericTypeArguments.FirstOrDefault() == trytb.Type || z.Value.PropertyType.GetElementType() == trytb.Type) && + z.Value.GetCustomAttribute()?.ManyToMany == pnvAttr.ManyToMany && + typeof(IEnumerable).IsAssignableFrom(z.Value.PropertyType)).Any(); + + if (isManyToMany == false) + { + nvref.Exception = new Exception($"【ManyToMany】导航属性 {trytbTypeName}.{pnv.Name} 解析错误,实体类型 {tbrefTypeName} 必须存在对应的 [Navigate(ManyToMany = x)] 集合属性"); + trytb.AddOrUpdateTableRef(pnv.Name, nvref); + //if (isLazy) throw nvref.Exception; + continue; + } + if (isManyToMany) + { + midType = pnvAttr.ManyToMany; + valiManyToMany(); + } + } + else + { + isManyToMany = propElementType != trytb.Type && + pnv.Name.EndsWith($"{tbref.CsName}s", StringComparison.CurrentCultureIgnoreCase) && + tbref.Properties.Where(z => (z.Value.PropertyType.GenericTypeArguments.FirstOrDefault() == trytb.Type || z.Value.PropertyType.GetElementType() == trytb.Type) && + z.Key.EndsWith($"{trytb.CsName}s", StringComparison.CurrentCultureIgnoreCase) && + typeof(IEnumerable).IsAssignableFrom(z.Value.PropertyType)).Any(); + } if (isManyToMany) { if (tbref.Primarys.Any() == false) @@ -308,116 +339,75 @@ namespace FreeSql.Internal //if (isLazy) throw nvref.Exception; continue; } + if (pnvAttr?.ManyToMany == null) + { + //中间表怎么查询,比如 Song、Tag、SongTag + var midFlagStr = string.Empty; + if (pnv.Name.Length >= tbref.CsName.Length - 1) + midFlagStr = pnv.Name.Remove(pnv.Name.Length - tbref.CsName.Length - 1); - //中间表怎么查询,比如 Song、Tag、SongTag - var midFlagStr = pnv.Name.Remove(pnv.Name.Length - tbref.CsName.Length - 1); + #region 在 trytb 命名空间下查找中间类 + if (midType == null) + { + midType = trytb.Type.IsNested ? + trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.Type.DeclaringType.Name}+{trytb.CsName}{tbref.CsName}{midFlagStr}", false, true) : //SongTag + trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.CsName}{tbref.CsName}{midFlagStr}", false, true); + valiManyToMany(); + } + if (midType == null) + { + midType = trytb.Type.IsNested ? + trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.Type.DeclaringType.Name}+{trytb.CsName}_{tbref.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true) : //Song_Tag + trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.CsName}_{tbref.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true); + valiManyToMany(); + } + if (midType == null) + { + midType = trytb.Type.IsNested ? + trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.Type.DeclaringType.Name}+{tbref.CsName}{trytb.CsName}{midFlagStr}", false, true) : //TagSong + trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{tbref.CsName}{trytb.CsName}{midFlagStr}", false, true); + valiManyToMany(); + } + if (midType == null) + { + midType = trytb.Type.IsNested ? + trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.Type.DeclaringType.Name}+{tbref.CsName}_{trytb.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true) : //Tag_Song + trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{tbref.CsName}_{trytb.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true); + valiManyToMany(); + } + #endregion - #region 在 trytb 命名空间下查找中间类 - midType = trytb.Type.IsNested ? - trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.Type.DeclaringType.Name}+{trytb.CsName}{tbref.CsName}{midFlagStr}", false, true) : //SongTag - trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.CsName}{tbref.CsName}{midFlagStr}", false, true); - if (midType != null) - { - var midTypeProps = midType.GetProperties(); - var midTypePropsTrytb = midTypeProps.Where(a => a.PropertyType == trytb.Type).Count(); - var midTypePropsTbref = midTypeProps.Where(a => a.PropertyType == tbref.Type).Count(); - if (midTypePropsTrytb != 1 || midTypePropsTbref != 1) midType = null; - } - if (midType == null) - { - midType = trytb.Type.IsNested ? - trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.Type.DeclaringType.Name}+{trytb.CsName}_{tbref.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true) : //Song_Tag - trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.CsName}_{tbref.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true); - if (midType != null) + #region 在 tbref 命名空间下查找中间类 + if (midType == null) { - var midTypeProps = midType.GetProperties(); - var midTypePropsTrytb = midTypeProps.Where(a => a.PropertyType == trytb.Type).Count(); - var midTypePropsTbref = midTypeProps.Where(a => a.PropertyType == tbref.Type).Count(); - if (midTypePropsTrytb != 1 || midTypePropsTbref != 1) midType = null; + midType = tbref.Type.IsNested ? + tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.Type.DeclaringType.Name}+{trytb.CsName}{tbref.CsName}{midFlagStr}", false, true) : //SongTag + tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{trytb.CsName}{tbref.CsName}{midFlagStr}", false, true); + valiManyToMany(); } - } - if (midType == null) - { - midType = trytb.Type.IsNested ? - trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.Type.DeclaringType.Name}+{tbref.CsName}{trytb.CsName}{midFlagStr}", false, true) : //TagSong - trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{tbref.CsName}{trytb.CsName}{midFlagStr}", false, true); - if (midType != null) + if (midType == null) { - var midTypeProps = midType.GetProperties(); - var midTypePropsTrytb = midTypeProps.Where(a => a.PropertyType == trytb.Type).Count(); - var midTypePropsTbref = midTypeProps.Where(a => a.PropertyType == tbref.Type).Count(); - if (midTypePropsTrytb != 1 || midTypePropsTbref != 1) midType = null; + midType = tbref.Type.IsNested ? + tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.Type.DeclaringType.Name}+{trytb.CsName}_{tbref.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true) : //Song_Tag + tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{trytb.CsName}_{tbref.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true); + valiManyToMany(); } - } - if (midType == null) - { - midType = trytb.Type.IsNested ? - trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{trytb.Type.DeclaringType.Name}+{tbref.CsName}_{trytb.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true) : //Tag_Song - trytb.Type.Assembly.GetType($"{trytb.Type.Namespace}.{tbref.CsName}_{trytb.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true); - if (midType != null) + if (midType == null) { - var midTypeProps = midType.GetProperties(); - var midTypePropsTrytb = midTypeProps.Where(a => a.PropertyType == trytb.Type).Count(); - var midTypePropsTbref = midTypeProps.Where(a => a.PropertyType == tbref.Type).Count(); - if (midTypePropsTrytb != 1 || midTypePropsTbref != 1) midType = null; + midType = tbref.Type.IsNested ? + tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.Type.DeclaringType.Name}+{tbref.CsName}{trytb.CsName}{midFlagStr}", false, true) : //TagSong + tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.CsName}{trytb.CsName}{midFlagStr}", false, true); + valiManyToMany(); } - } - #endregion - - #region 在 tbref 命名空间下查找中间类 - if (midType == null) - { - midType = tbref.Type.IsNested ? - tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.Type.DeclaringType.Name}+{trytb.CsName}{tbref.CsName}{midFlagStr}", false, true) : //SongTag - tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{trytb.CsName}{tbref.CsName}{midFlagStr}", false, true); - if (midType != null) + if (midType == null) { - var midTypeProps = midType.GetProperties(); - var midTypePropsTrytb = midTypeProps.Where(a => a.PropertyType == trytb.Type).Count(); - var midTypePropsTbref = midTypeProps.Where(a => a.PropertyType == tbref.Type).Count(); - if (midTypePropsTrytb != 1 || midTypePropsTbref != 1) midType = null; + midType = tbref.Type.IsNested ? + tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.Type.DeclaringType.Name}+{tbref.CsName}_{trytb.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true) : //Tag_Song + tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.CsName}_{trytb.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true); + valiManyToMany(); } + #endregion } - if (midType == null) - { - midType = tbref.Type.IsNested ? - tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.Type.DeclaringType.Name}+{trytb.CsName}_{tbref.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true) : //Song_Tag - tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{trytb.CsName}_{tbref.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true); - if (midType != null) - { - var midTypeProps = midType.GetProperties(); - var midTypePropsTrytb = midTypeProps.Where(a => a.PropertyType == trytb.Type).Count(); - var midTypePropsTbref = midTypeProps.Where(a => a.PropertyType == tbref.Type).Count(); - if (midTypePropsTrytb != 1 || midTypePropsTbref != 1) midType = null; - } - } - if (midType == null) - { - midType = tbref.Type.IsNested ? - tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.Type.DeclaringType.Name}+{tbref.CsName}{trytb.CsName}{midFlagStr}", false, true) : //TagSong - tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.CsName}{trytb.CsName}{midFlagStr}", false, true); - if (midType != null) - { - var midTypeProps = midType.GetProperties(); - var midTypePropsTrytb = midTypeProps.Where(a => a.PropertyType == trytb.Type).Count(); - var midTypePropsTbref = midTypeProps.Where(a => a.PropertyType == tbref.Type).Count(); - if (midTypePropsTrytb != 1 || midTypePropsTbref != 1) midType = null; - } - } - if (midType == null) - { - midType = tbref.Type.IsNested ? - tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.Type.DeclaringType.Name}+{tbref.CsName}_{trytb.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true) : //Tag_Song - tbref.Type.Assembly.GetType($"{tbref.Type.Namespace}.{tbref.CsName}_{trytb.CsName}{(string.IsNullOrEmpty(midFlagStr) ? "" : "_")}{midFlagStr}", false, true); - if (midType != null) - { - var midTypeProps = midType.GetProperties(); - var midTypePropsTrytb = midTypeProps.Where(a => a.PropertyType == trytb.Type).Count(); - var midTypePropsTbref = midTypeProps.Where(a => a.PropertyType == tbref.Type).Count(); - if (midTypePropsTrytb != 1 || midTypePropsTbref != 1) midType = null; - } - } - #endregion isManyToMany = midType != null; } @@ -427,78 +417,164 @@ namespace FreeSql.Internal var midTypePropsTrytb = tbmid.Properties.Where(a => a.Value.PropertyType == trytb.Type).FirstOrDefault().Value; //g.mysql.Select().Where(a => g.mysql.Select().Where(b => b.Tag_id == a.Id && b.Song_id == 1).Any()); var lmbdWhere = isLazy ? new StringBuilder() : null; - for (var a = 0; a < trytb.Primarys.Length; a++) + + if (pnvAttr?.ManyToMany != null) { - var findtrytbPkCsName = trytb.Primarys[a].CsName.TrimStart('_'); - if (findtrytbPkCsName.StartsWith(trytb.Type.Name, StringComparison.CurrentCultureIgnoreCase)) findtrytbPkCsName = findtrytbPkCsName.Substring(trytb.Type.Name.Length).TrimStart('_'); - if (tbmid.ColumnsByCs.TryGetValue($"{midTypePropsTrytb.Name}{findtrytbPkCsName}", out var trycol) == false && //骆峰命名 - tbmid.ColumnsByCs.TryGetValue($"{midTypePropsTrytb.Name}_{findtrytbPkCsName}", out trycol) == false //下划线命名 - ) + #region 指定 Navigate[ManyToMany = x] 配置多对多关系 + TableRef trytbTf = null; + try { - + trytbTf = tbmid.GetTableRef(midTypePropsTrytb.Name, true); } - if (trycol != null && trycol.CsType.NullableTypeOrThis() != trytb.Primarys[a].CsType) + catch (Exception ex) { - nvref.Exception = new Exception($"【ManyToMany】导航属性 {trytbTypeName}.{pnv.Name} 解析错误,{tbmid.CsName}.{trycol.CsName} 和 {trytb.CsName}.{trytb.Primarys[a].CsName} 类型不一致"); + nvref.Exception = new Exception($"【ManyToMany】导航属性 {trytbTypeName}.{pnv.Name} 解析错误,中间类 {tbmid.CsName}.{midTypePropsTrytb.Name} 错误:{ex.Message}"); trytb.AddOrUpdateTableRef(pnv.Name, nvref); //if (isLazy) throw nvref.Exception; - break; } - if (trycol == null) + if (nvref.Exception == null) { - nvref.Exception = new Exception($"【ManyToMany】导航属性 {trytbTypeName}.{pnv.Name} 在 {tbmid.CsName} 中没有找到对应的字段,如:{midTypePropsTrytb.Name}{findtrytbPkCsName}、{midTypePropsTrytb.Name}_{findtrytbPkCsName}"); - trytb.AddOrUpdateTableRef(pnv.Name, nvref); - //if (isLazy) throw nvref.Exception; - break; + if (trytbTf.RefType != TableRefType.ManyToOne && trytbTf.RefType != TableRefType.OneToOne) + { + nvref.Exception = new Exception($"【ManyToMany】导航属性 {trytbTypeName}.{pnv.Name} 解析错误,中间类 {tbmid.CsName}.{midTypePropsTrytb.Name} 导航属性不是【ManyToOne】或【OneToOne】"); + trytb.AddOrUpdateTableRef(pnv.Name, nvref); + //if (isLazy) throw nvref.Exception; + } + else + { + nvref.Columns.AddRange(trytbTf.RefColumns); + nvref.MiddleColumns.AddRange(trytbTf.Columns); + + if (tbmid.Primarys.Any() == false) + trytbTf.Columns.Select(c => tbmid.ColumnsByCs[c.CsName].Attribute.IsPrimary = true); + if (isLazy) + { + for (var a = 0; a < trytbTf.RefColumns.Count; a++) + { + if (a > 0) lmbdWhere.Append(" && "); + lmbdWhere.Append("b.").Append(trytbTf.Columns[a].CsName).Append(" == this.").Append(trytbTf.RefColumns[a].CsName); + } + } + } } - - nvref.Columns.Add(trytb.Primarys[a]); - nvref.MiddleColumns.Add(trycol); - if (tbmid.Primarys.Any() == false) - trycol.Attribute.IsPrimary = true; - - if (isLazy) + if (nvref.Exception == null) { - if (a > 0) lmbdWhere.Append(" && "); - lmbdWhere.Append("b.").Append(trycol.CsName).Append(" == this.").Append(trytb.Primarys[a].CsName); + var midTypePropsTbref = tbmid.Properties.Where(a => a.Value.PropertyType == tbref.Type).FirstOrDefault().Value; + + TableRef tbrefTf = null; + try + { + tbrefTf = tbmid.GetTableRef(midTypePropsTbref.Name, true); + } + catch (Exception ex) + { + nvref.Exception = new Exception($"【ManyToMany】导航属性 {tbrefTypeName}.{pnv.Name} 解析错误,中间类 {tbmid.CsName}.{midTypePropsTbref.Name} 错误:{ex.Message}"); + trytb.AddOrUpdateTableRef(pnv.Name, nvref); + //if (isLazy) throw nvref.Exception; + } + if (nvref.Exception == null) + { + if (tbrefTf.RefType != TableRefType.ManyToOne && tbrefTf.RefType != TableRefType.OneToOne) + { + nvref.Exception = new Exception($"【ManyToMany】导航属性 {tbrefTypeName}.{pnv.Name} 解析错误,中间类 {tbmid.CsName}.{midTypePropsTbref.Name} 导航属性不是【ManyToOne】或【OneToOne】"); + trytb.AddOrUpdateTableRef(pnv.Name, nvref); + //if (isLazy) throw nvref.Exception; + } + else + { + nvref.RefColumns.AddRange(tbrefTf.RefColumns); + nvref.MiddleColumns.AddRange(tbrefTf.Columns); + + if (tbmid.Primarys.Any() == false) + tbrefTf.Columns.Select(c => tbmid.ColumnsByCs[c.CsName].Attribute.IsPrimary = true); + + if (isLazy) + { + for (var a = 0; a < tbrefTf.RefColumns.Count; a++) + lmbdWhere.Append(" && b.").Append(tbrefTf.Columns[a].CsName).Append(" == a.").Append(tbrefTf.RefColumns[a].CsName); + } + } + } } + #endregion } - - if (nvref.Exception == null) + else { - var midTypePropsTbref = tbmid.Properties.Where(a => a.Value.PropertyType == tbref.Type).FirstOrDefault().Value; - for (var a = 0; a < tbref.Primarys.Length; a++) + #region 约定配置 + for (var a = 0; a < trytb.Primarys.Length; a++) { - var findtbrefPkCsName = tbref.Primarys[a].CsName.TrimStart('_'); - if (findtbrefPkCsName.StartsWith(tbref.Type.Name, StringComparison.CurrentCultureIgnoreCase)) findtbrefPkCsName = findtbrefPkCsName.Substring(tbref.Type.Name.Length).TrimStart('_'); - if (tbmid.ColumnsByCs.TryGetValue($"{midTypePropsTbref.Name}{findtbrefPkCsName}", out var trycol) == false && //骆峰命名 - tbmid.ColumnsByCs.TryGetValue($"{midTypePropsTbref.Name}_{findtbrefPkCsName}", out trycol) == false //下划线命名 + var findtrytbPkCsName = trytb.Primarys[a].CsName.TrimStart('_'); + if (findtrytbPkCsName.StartsWith(trytb.Type.Name, StringComparison.CurrentCultureIgnoreCase)) findtrytbPkCsName = findtrytbPkCsName.Substring(trytb.Type.Name.Length).TrimStart('_'); + if (tbmid.ColumnsByCs.TryGetValue($"{midTypePropsTrytb.Name}{findtrytbPkCsName}", out var trycol) == false && //骆峰命名 + tbmid.ColumnsByCs.TryGetValue($"{midTypePropsTrytb.Name}_{findtrytbPkCsName}", out trycol) == false //下划线命名 ) { } - if (trycol != null && trycol.CsType.NullableTypeOrThis() != tbref.Primarys[a].CsType) + if (trycol != null && trycol.CsType.NullableTypeOrThis() != trytb.Primarys[a].CsType) { - nvref.Exception = new Exception($"【ManyToMany】导航属性 {trytbTypeName}.{pnv.Name} 解析错误,{tbmid.CsName}.{trycol.CsName} 和 {tbref.CsName}.{tbref.Primarys[a].CsName} 类型不一致"); + nvref.Exception = new Exception($"【ManyToMany】导航属性 {trytbTypeName}.{pnv.Name} 解析错误,{tbmid.CsName}.{trycol.CsName} 和 {trytb.CsName}.{trytb.Primarys[a].CsName} 类型不一致"); trytb.AddOrUpdateTableRef(pnv.Name, nvref); //if (isLazy) throw nvref.Exception; break; } if (trycol == null) { - nvref.Exception = new Exception($"【ManyToMany】导航属性 {trytbTypeName}.{pnv.Name} 在 {tbmid.CsName} 中没有找到对应的字段,如:{midTypePropsTbref.Name}{findtbrefPkCsName}、{midTypePropsTbref.Name}_{findtbrefPkCsName}"); + nvref.Exception = new Exception($"【ManyToMany】导航属性 {trytbTypeName}.{pnv.Name} 在 {tbmid.CsName} 中没有找到对应的字段,如:{midTypePropsTrytb.Name}{findtrytbPkCsName}、{midTypePropsTrytb.Name}_{findtrytbPkCsName}"); trytb.AddOrUpdateTableRef(pnv.Name, nvref); //if (isLazy) throw nvref.Exception; break; } - nvref.RefColumns.Add(tbref.Primarys[a]); + nvref.Columns.Add(trytb.Primarys[a]); nvref.MiddleColumns.Add(trycol); if (tbmid.Primarys.Any() == false) trycol.Attribute.IsPrimary = true; - if (isLazy) lmbdWhere.Append(" && b.").Append(trycol.CsName).Append(" == a.").Append(tbref.Primarys[a].CsName); + if (isLazy) + { + if (a > 0) lmbdWhere.Append(" && "); + lmbdWhere.Append("b.").Append(trycol.CsName).Append(" == this.").Append(trytb.Primarys[a].CsName); + } } + + if (nvref.Exception == null) + { + var midTypePropsTbref = tbmid.Properties.Where(a => a.Value.PropertyType == tbref.Type).FirstOrDefault().Value; + for (var a = 0; a < tbref.Primarys.Length; a++) + { + var findtbrefPkCsName = tbref.Primarys[a].CsName.TrimStart('_'); + if (findtbrefPkCsName.StartsWith(tbref.Type.Name, StringComparison.CurrentCultureIgnoreCase)) findtbrefPkCsName = findtbrefPkCsName.Substring(tbref.Type.Name.Length).TrimStart('_'); + if (tbmid.ColumnsByCs.TryGetValue($"{midTypePropsTbref.Name}{findtbrefPkCsName}", out var trycol) == false && //骆峰命名 + tbmid.ColumnsByCs.TryGetValue($"{midTypePropsTbref.Name}_{findtbrefPkCsName}", out trycol) == false //下划线命名 + ) + { + + } + if (trycol != null && trycol.CsType.NullableTypeOrThis() != tbref.Primarys[a].CsType) + { + nvref.Exception = new Exception($"【ManyToMany】导航属性 {trytbTypeName}.{pnv.Name} 解析错误,{tbmid.CsName}.{trycol.CsName} 和 {tbref.CsName}.{tbref.Primarys[a].CsName} 类型不一致"); + trytb.AddOrUpdateTableRef(pnv.Name, nvref); + //if (isLazy) throw nvref.Exception; + break; + } + if (trycol == null) + { + nvref.Exception = new Exception($"【ManyToMany】导航属性 {trytbTypeName}.{pnv.Name} 在 {tbmid.CsName} 中没有找到对应的字段,如:{midTypePropsTbref.Name}{findtbrefPkCsName}、{midTypePropsTbref.Name}_{findtbrefPkCsName}"); + trytb.AddOrUpdateTableRef(pnv.Name, nvref); + //if (isLazy) throw nvref.Exception; + break; + } + + nvref.RefColumns.Add(tbref.Primarys[a]); + nvref.MiddleColumns.Add(trycol); + if (tbmid.Primarys.Any() == false) + trycol.Attribute.IsPrimary = true; + + if (isLazy) lmbdWhere.Append(" && b.").Append(trycol.CsName).Append(" == a.").Append(tbref.Primarys[a].CsName); + } + } + #endregion } if (nvref.Columns.Count > 0 && nvref.RefColumns.Count > 0) { @@ -586,7 +662,7 @@ namespace FreeSql.Internal var findtrytbPkCsName = trytb.Primarys[a].CsName.TrimStart('_'); if (findtrytbPkCsName.StartsWith(trytb.Type.Name, StringComparison.CurrentCultureIgnoreCase)) findtrytbPkCsName = findtrytbPkCsName.Substring(trytb.Type.Name.Length).TrimStart('_'); var findtrytb = pnv.Name; - if (findtrytb.EndsWith(tbref.CsName + "s")) findtrytb = findtrytb.Substring(0, findtrytb.Length - tbref.CsName.Length - 1); + if (findtrytb.EndsWith($"{tbref.CsName}s", StringComparison.CurrentCultureIgnoreCase)) findtrytb = findtrytb.Substring(0, findtrytb.Length - tbref.CsName.Length - 1); findtrytb += trytb.CsName; var trycol = bindColumns.Any() ? bindColumns[a] : null; diff --git a/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj b/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj index 358dca55..bfb97595 100644 --- a/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj +++ b/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj @@ -2,7 +2,7 @@ netstandard2.0;net452 - 0.7.8 + 0.7.9 true YeXiangQin FreeSql 数据库实现,基于 MySql 5.6 diff --git a/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj b/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj index 6e2a2afe..e09830e6 100644 --- a/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj +++ b/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.7.8 + 0.7.9 true YeXiangQin FreeSql 数据库实现,基于 MySql 5.6 diff --git a/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj b/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj index 64c33afb..dcdbff8f 100644 --- a/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj +++ b/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.7.8 + 0.7.9 true YeXiangQin FreeSql 数据库实现,基于 Oracle 11 diff --git a/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj b/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj index fb69e0c4..b21b82fe 100644 --- a/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj +++ b/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.7.8 + 0.7.9 true YeXiangQin FreeSql 数据库实现,基于 PostgreSQL 9.5 diff --git a/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj b/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj index 383bd572..d2e507d3 100644 --- a/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj +++ b/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj @@ -2,7 +2,7 @@ netstandard2.0;net451 - 0.7.8 + 0.7.9 true YeXiangQin FreeSql 数据库实现,基于 SqlServer 2005+,并根据版本适配分页方法:row_number 或 offset fetch next diff --git a/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj b/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj index f0cae953..4c53f365 100644 --- a/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj +++ b/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.7.8 + 0.7.9 true YeXiangQin FreeSql 数据库实现,基于 Sqlite 3.0