From da7bb7c74d9edda169b89ea77d5488b5b9425a58 Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Thu, 2 Mar 2023 15:46:45 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20[Navigate(xx,=20TempPr?= =?UTF-8?q?imary=20=3D=20xx)]=20=E4=B8=8E=E9=9D=9E=E4=B8=BB=E9=94=AE?= =?UTF-8?q?=E5=85=B3=E8=81=94=EF=BC=9B=EF=BC=88=E4=BB=85=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AggregateRootUtils.cs | 2 +- .../FreeSql.Extensions.AggregateRoot.csproj | 4 +- FreeSql.DbContext/DbSet/DbSetAsync.cs | 4 +- FreeSql.DbContext/DbSet/DbSetSync.cs | 4 +- FreeSql/DataAnnotations/NavigateAttribute.cs | 7 + FreeSql/DataAnnotations/TableFluent.cs | 18 +- FreeSql/Extensions/FreeSqlGlobalExtensions.cs | 2 +- FreeSql/FreeSql.xml | 6 + FreeSql/FreeSqlBuilder.cs | 12 +- FreeSql/Internal/CommonExpression.cs | 8 +- .../SelectProvider/Select1Provider.cs | 4 +- FreeSql/Internal/CommonUtils.cs | 2 + FreeSql/Internal/Model/TableInfo.cs | 15 +- FreeSql/Internal/UtilsExpressionTree.cs | 256 +++++++++++++----- 14 files changed, 243 insertions(+), 101 deletions(-) diff --git a/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootUtils.cs b/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootUtils.cs index 3f09558c..1f475509 100644 --- a/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootUtils.cs +++ b/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootUtils.cs @@ -377,7 +377,7 @@ namespace FreeSql continue; } if (cascade == false) continue; - var tbref = table.GetTableRef(prop.Name, false); + var tbref = table.GetTableRef(prop.Name, false, false); if (tbref == null) continue; var boundaryAttr = GetPropertyBoundaryAttribute(prop, boundaryName); if (boundaryAttr?.Break == true) continue; diff --git a/Extensions/FreeSql.Extensions.AggregateRoot/FreeSql.Extensions.AggregateRoot.csproj b/Extensions/FreeSql.Extensions.AggregateRoot/FreeSql.Extensions.AggregateRoot.csproj index f374a87b..0bee3726 100644 --- a/Extensions/FreeSql.Extensions.AggregateRoot/FreeSql.Extensions.AggregateRoot.csproj +++ b/Extensions/FreeSql.Extensions.AggregateRoot/FreeSql.Extensions.AggregateRoot.csproj @@ -18,7 +18,7 @@ true key.snk false - 1.0.6 + 3.2.690-preview20230302 @@ -26,7 +26,7 @@ - + diff --git a/FreeSql.DbContext/DbSet/DbSetAsync.cs b/FreeSql.DbContext/DbSet/DbSetAsync.cs index 82fcc7fd..3566be9d 100644 --- a/FreeSql.DbContext/DbSet/DbSetAsync.cs +++ b/FreeSql.DbContext/DbSet/DbSetAsync.cs @@ -151,7 +151,7 @@ namespace FreeSql if (_table.Properties.TryGetValue(propertyName, out var prop) == false) throw new KeyNotFoundException(DbContextStrings.NotFound_Property(_table.Type.FullName, propertyName)); if (_table.ColumnsByCsIgnore.ContainsKey(propertyName)) throw new ArgumentException(DbContextStrings.TypeHasSetProperty_IgnoreAttribute(_table.Type.FullName, propertyName)); - var tref = _table.GetTableRef(propertyName, true); + var tref = _table.GetTableRef(propertyName, true, false); if (tref == null) return; switch (tref.RefType) { @@ -209,7 +209,7 @@ namespace FreeSql if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return; if (_table.ColumnsByCs.ContainsKey(prop.Name)) return; - var tref = _table.GetTableRef(prop.Name, false); //防止非正常的导航属性报错 + var tref = _table.GetTableRef(prop.Name, false, false); //防止非正常的导航属性报错 if (tref == null) return; DbSet refSet = null; switch (tref.RefType) diff --git a/FreeSql.DbContext/DbSet/DbSetSync.cs b/FreeSql.DbContext/DbSet/DbSetSync.cs index 842733ba..e08ae803 100644 --- a/FreeSql.DbContext/DbSet/DbSetSync.cs +++ b/FreeSql.DbContext/DbSet/DbSetSync.cs @@ -162,7 +162,7 @@ namespace FreeSql if (_table.Properties.TryGetValue(propertyName, out var prop) == false) throw new KeyNotFoundException(DbContextStrings.NotFound_Property(_table.Type.FullName, propertyName)); if (_table.ColumnsByCsIgnore.ContainsKey(propertyName)) throw new ArgumentException(DbContextStrings.TypeHasSetProperty_IgnoreAttribute(_table.Type.FullName, propertyName)); - var tref = _table.GetTableRef(propertyName, true); + var tref = _table.GetTableRef(propertyName, true, false); if (tref == null) return; switch (tref.RefType) { @@ -220,7 +220,7 @@ namespace FreeSql if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return; if (_table.ColumnsByCs.ContainsKey(prop.Name)) return; - var tref = _table.GetTableRef(prop.Name, false); //防止非正常的导航属性报错 + var tref = _table.GetTableRef(prop.Name, false, false); //防止非正常的导航属性报错 if (tref == null) return; DbSet refSet = null; switch (tref.RefType) diff --git a/FreeSql/DataAnnotations/NavigateAttribute.cs b/FreeSql/DataAnnotations/NavigateAttribute.cs index f1aa3058..b3aac1d6 100644 --- a/FreeSql/DataAnnotations/NavigateAttribute.cs +++ b/FreeSql/DataAnnotations/NavigateAttribute.cs @@ -22,6 +22,13 @@ namespace FreeSql.DataAnnotations /// _________________public List<Topic> Topics { get; set; } /// public string Bind { get; set; } + + /// + /// 与非主键进行关联,仅支持 OneToMany、ManyToOne + /// 使用方法参考 Bind 属性 + /// + public string TempPrimary { get; set; } + /// /// 手工绑定 ManyToMany 导航关系 /// diff --git a/FreeSql/DataAnnotations/TableFluent.cs b/FreeSql/DataAnnotations/TableFluent.cs index 6d2666e1..83f5735c 100644 --- a/FreeSql/DataAnnotations/TableFluent.cs +++ b/FreeSql/DataAnnotations/TableFluent.cs @@ -60,10 +60,12 @@ namespace FreeSql.DataAnnotations /// /// 多对多关系的中间实体类型 /// - public TableFluent Navigate(string proto, string bind, Type manyToMany = null) + public TableFluent Navigate(string proto, string bind, Type manyToMany = null) => NavigateInternal(proto, bind, null, manyToMany); + public TableFluent Navigate(string proto, string bind, string tempPrimary) => NavigateInternal(proto, bind, tempPrimary, null); + TableFluent NavigateInternal(string proto, string bind, string tempPrimary, Type manyToMany) { if (_properties.TryGetValue(proto, out var tryProto) == false) throw new KeyNotFoundException(CoreStrings.NotFound_Property(proto)); - var nav = new NavigateAttribute { Bind = bind, ManyToMany = manyToMany }; + var nav = new NavigateAttribute { Bind = bind, TempPrimary = tempPrimary, ManyToMany = manyToMany }; _table._navigates.AddOrUpdate(tryProto.Name, nav, (name, old) => nav); return this; } @@ -148,18 +150,22 @@ namespace FreeSql.DataAnnotations /// /// 多对多关系的中间实体类型 /// - public TableFluent Navigate(Expression> proto, string bind, Type manyToMany = null) + public TableFluent Navigate(Expression> proto, string bind, Type manyToMany = null) => NavigateInternal(proto, bind, null, manyToMany); + public TableFluent Navigate(Expression> proto, string bind, string tempPrimary) => NavigateInternal(proto, bind, tempPrimary, null); + TableFluent NavigateInternal(Expression> proto, string bind, string tempPrimary, Type manyToMany = null) { var exp = proto?.Body; if (exp.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; var member = (exp as MemberExpression)?.Member; if (member == null) throw new FormatException(CoreStrings.Bad_Expression_Format(proto)); - return Navigate(member.Name, bind, manyToMany); + return NavigateInternal(member.Name, bind, tempPrimary, manyToMany); } - public TableFluent Navigate(string proto, string bind, Type manyToMany = null) + public TableFluent Navigate(string proto, string bind, Type manyToMany = null) => NavigateInternal(proto, bind, null, manyToMany); + public TableFluent Navigate(string proto, string bind, string tempPrimary) => NavigateInternal(proto, bind, tempPrimary, null); + TableFluent NavigateInternal(string proto, string bind, string tempPrimary, Type manyToMany) { if (_properties.TryGetValue(proto, out var tryProto) == false) throw new KeyNotFoundException(CoreStrings.NotFound_PropertyName(proto)); - var nav = new NavigateAttribute { Bind = bind, ManyToMany = manyToMany }; + var nav = new NavigateAttribute { Bind = bind, TempPrimary = tempPrimary, ManyToMany = manyToMany }; _table._navigates.AddOrUpdate(tryProto.Name, nav, (name, old) => nav); return this; } diff --git a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs index 7ce2c34c..12012b83 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs @@ -409,7 +409,7 @@ public static partial class FreeSqlGlobalExtensions #endif return list; } - var tbtr = t1tb.GetTableRef(props[0], true); + var tbtr = t1tb.GetTableRef(props[0], true, true); if (tbtr == null) throw new ArgumentException(CoreStrings.ParameterError_NotValid_Navigation(nameof(property))); var reftb = orm.CodeFirst.GetTableByEntity(t1exp.Type); var refsel = orm.Select().AsType(t1exp.Type) as Select1Provider; diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 21395735..abda9cfe 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -385,6 +385,12 @@ _________________public List<Topic> Topics { get; set; } + + + 与非主键进行关联,仅支持 OneToMany、ManyToOne + 使用方法参考 Bind 属性 + + 手工绑定 ManyToMany 导航关系 diff --git a/FreeSql/FreeSqlBuilder.cs b/FreeSql/FreeSqlBuilder.cs index c1ed71ba..3a9898a5 100644 --- a/FreeSql/FreeSqlBuilder.cs +++ b/FreeSql/FreeSqlBuilder.cs @@ -375,29 +375,29 @@ namespace FreeSql switch (_nameConvertType) { case NameConvertType.ToLower: - ret.Aop.ConfigEntity += (_, e) => e.ModifyResult.Name = e.ModifyResult.Name?.ToLower(); + ret.Aop.ConfigEntity += (_, e) => { if (string.IsNullOrWhiteSpace(e.ModifyResult.AsTable)) e.ModifyResult.Name = e.ModifyResult.Name?.ToLower(); }; ret.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = e.ModifyResult.Name?.ToLower(); ret.CodeFirst.IsSyncStructureToLower = true; break; case NameConvertType.ToUpper: - ret.Aop.ConfigEntity += (_, e) => e.ModifyResult.Name = e.ModifyResult.Name?.ToUpper(); + ret.Aop.ConfigEntity += (_, e) => { if (string.IsNullOrWhiteSpace(e.ModifyResult.AsTable)) e.ModifyResult.Name = e.ModifyResult.Name?.ToUpper(); }; ret.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = e.ModifyResult.Name?.ToUpper(); ret.CodeFirst.IsSyncStructureToUpper = true; break; case NameConvertType.PascalCaseToUnderscore: - ret.Aop.ConfigEntity += (_, e) => e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name); + ret.Aop.ConfigEntity += (_, e) => { if (string.IsNullOrWhiteSpace(e.ModifyResult.AsTable)) e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name); }; ret.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name); break; case NameConvertType.PascalCaseToUnderscoreWithLower: - ret.Aop.ConfigEntity += (_, e) => e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name)?.ToLower(); + ret.Aop.ConfigEntity += (_, e) => { if (string.IsNullOrWhiteSpace(e.ModifyResult.AsTable)) e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name)?.ToLower(); }; ret.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name)?.ToLower(); break; case NameConvertType.PascalCaseToUnderscoreWithUpper: - ret.Aop.ConfigEntity += (_, e) => e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name)?.ToUpper(); + ret.Aop.ConfigEntity += (_, e) => { if (string.IsNullOrWhiteSpace(e.ModifyResult.AsTable)) e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name)?.ToUpper(); }; ret.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name)?.ToUpper(); break; //case NameConvertType.UnderscoreToPascalCase: - // ret.Aop.ConfigEntity += (_, e) => e.ModifyResult.Name = UnderScorePascalCase(e.ModifyResult.Name); + // ret.Aop.ConfigEntity += (_, e) => { if (string.IsNullOrWhiteSpace(e.ModifyResult.AsTable)) e.ModifyResult.Name = UnderScorePascalCase(e.ModifyResult.Name); }; // ret.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = UnderScorePascalCase(e.ModifyResult.Name); // break; default: diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index f2026d8c..d9f6f586 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -1428,7 +1428,7 @@ namespace FreeSql.Internal } var parm123Tb = _common.GetTableByEntity(asSelectParentExp.Type); - var parm123Ref = parm123Tb.GetTableRef(asSelectParentExp1.Member.Name, true); + var parm123Ref = parm123Tb.GetTableRef(asSelectParentExp1.Member.Name, true, true); if (parm123Ref != null) { if (parm123Ref.RefType == TableRefType.PgArrayToMany) @@ -1902,7 +1902,7 @@ namespace FreeSql.Internal { //导航条件,OneToOne、ManyToOne var firstTb = tsc._tables.First().Table; var parentTb = _common.GetTableByEntity(mp.Expression.Type); - var parentTbRef = parentTb?.GetTableRef(mp.Member.Name, tsc.style == ExpressionStyle.AsSelect); + var parentTbRef = parentTb?.GetTableRef(mp.Member.Name, tsc.style == ExpressionStyle.AsSelect, true); if (parentTbRef != null) { Expression navCondExp = null; @@ -2015,7 +2015,7 @@ namespace FreeSql.Internal } if (tb2.ColumnsByCsIgnore.ContainsKey(mp2.Member.Name)) throw new ArgumentException(CoreStrings.Ignored_Check_Confirm_PublicGetSet(tb2.DbName, mp2.Member.Name)); - if (tb2.GetTableRef(mp2.Member.Name, false) != null) + if (tb2.GetTableRef(mp2.Member.Name, false, true) != null) throw new ArgumentException(CoreStrings.Navigation_Missing_AsSelect(tb2.DbName, mp2.Member.Name)); throw new ArgumentException(CoreStrings.NotFound_Column(tb2.DbName, mp2.Member.Name)); } @@ -2718,7 +2718,7 @@ namespace FreeSql.Internal } if (select != null) return; memberExp = tmpExp; - memberTbref = exp3Tb.GetTableRef(memberExp.Member.Name, false); + memberTbref = exp3Tb.GetTableRef(memberExp.Member.Name, false, true); if (memberTbref == null) return; switch (memberTbref.RefType) { diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs index b9189798..76d6164a 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs @@ -503,7 +503,7 @@ namespace FreeSql.Internal.CommonProvider if (memExp == null) throw new ArgumentException($"{CoreStrings.Cannot_Resolve_ExpressionTree(nameof(property))}2"); var parTb = _commonUtils.GetTableByEntity(memExp.Expression.Type); if (parTb == null) throw new ArgumentException($"{CoreStrings.Cannot_Resolve_ExpressionTree(nameof(property))}3"); - var parTbref = parTb.GetTableRef(memExp.Member.Name, true); + var parTbref = parTb.GetTableRef(memExp.Member.Name, true, true); if (parTbref == null) throw new ArgumentException(CoreStrings.Not_Valid_Navigation_Property(nameof(property))); switch (parTbref.RefType) { @@ -682,7 +682,7 @@ namespace FreeSql.Internal.CommonProvider var tbrefOneToManyColumns = new List>(); //临时 OneToMany 三个表关联,第三个表需要前两个表确定 if (whereExp == null) { - tbref = tb.GetTableRef(collMem.Member.Name, true); + tbref = tb.GetTableRef(collMem.Member.Name, true, true); if (tbref == null) throw new Exception(CoreStrings.IncludeMany_NotValid_Navigation(tb.Type.DisplayCsharp(), collMem.Member.Name)); } else diff --git a/FreeSql/Internal/CommonUtils.cs b/FreeSql/Internal/CommonUtils.cs index c7308b6f..1e07f2e8 100644 --- a/FreeSql/Internal/CommonUtils.cs +++ b/FreeSql/Internal/CommonUtils.cs @@ -352,6 +352,7 @@ namespace FreeSql.Internal if (dicConfigEntity.TryGetValue(type, out var trytb) && trytb._navigates.TryGetValue(proto.Name, out var trynav)) { if (!string.IsNullOrEmpty(trynav.Bind)) attr.Bind = trynav.Bind; + if (!string.IsNullOrEmpty(trynav.TempPrimary)) attr.TempPrimary = trynav.TempPrimary; if (trynav.ManyToMany != null) attr.ManyToMany = trynav.ManyToMany; } break; @@ -362,6 +363,7 @@ namespace FreeSql.Internal trynav = tryattrobj as NavigateAttribute; if (trynav == null) continue; if (!string.IsNullOrEmpty(trynav.Bind)) attr.Bind = trynav.Bind; + if (!string.IsNullOrEmpty(trynav.TempPrimary)) attr.TempPrimary = trynav.TempPrimary; if (trynav.ManyToMany != null) attr.ManyToMany = trynav.ManyToMany; } break; diff --git a/FreeSql/Internal/Model/TableInfo.cs b/FreeSql/Internal/Model/TableInfo.cs index 5ba67184..56db4fbf 100644 --- a/FreeSql/Internal/Model/TableInfo.cs +++ b/FreeSql/Internal/Model/TableInfo.cs @@ -38,7 +38,7 @@ namespace FreeSql.Internal.Model { _refs.AddOrUpdate(propertyName, tbref, (ok, ov) => tbref); } - public TableRef GetTableRef(string propertyName, bool isThrowException) + public TableRef GetTableRef(string propertyName, bool isThrowException, bool isCascadeQuery = true) { if (_refs.TryGetValue(propertyName, out var tryref) == false) return null; if (tryref.Exception != null) @@ -46,6 +46,18 @@ namespace FreeSql.Internal.Model if (isThrowException) throw tryref.Exception; return null; } + if (isCascadeQuery == false && tryref.IsTempPrimary == true) + { + if (isThrowException) + { + switch (tryref.RefType) + { + case TableRefType.OneToMany: throw new Exception($"[Navigate(\"{string.Join(",", tryref.RefColumns.Select(a => a.CsName))}\", TempPrimary = \"{string.Join(",", tryref.Columns.Select(a => a.CsName))}\")] Only cascade query are supported"); + case TableRefType.ManyToOne: throw new Exception($"[Navigate(\"{string.Join(",", tryref.Columns.Select(a => a.CsName))}\", TempPrimary = \"{string.Join(",", tryref.RefColumns.Select(a => a.CsName))}\")] Only cascade query are supported"); + } + } + return null; + } return tryref; } public IEnumerable> GetAllTableRef() => _refs; @@ -160,6 +172,7 @@ namespace FreeSql.Internal.Model public List RefColumns { get; set; } = new List(); public Exception Exception { get; set; } + public bool IsTempPrimary { get; set; } } public enum TableRefType { diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index 34c1e7bc..cdc50759 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -623,12 +623,188 @@ namespace FreeSql.Internal var pnvAttr = common.GetEntityNavigateAttribute(trytb.Type, pnv); var pnvBind = pnvAttr?.Bind?.Split(',').Select(a => a.Trim()).Where(a => !string.IsNullOrEmpty(a)).ToArray(); + var pnvBindTempPrimary = pnvAttr?.TempPrimary?.Split(',').Select(a => a.Trim()).Where(a => !string.IsNullOrEmpty(a)).ToArray(); var nvref = new TableRef(); nvref.Property = pnv; //List 或 ICollection,一对多、多对多 var propElementType = pnv.PropertyType.GetGenericArguments().FirstOrDefault() ?? pnv.PropertyType.GetElementType(); var propTypeIsObservableCollection = propElementType != null && pnv.PropertyType == typeof(ObservableCollection<>).MakeGenericType(propElementType); + + #region islazy + void LocalManyLazyLoadingCode(PropertyInfo refprop, string cscodeExtLogic1, string cscodeExtLogic2, string lmbdWhere) + { + cscode.Append(" private bool __lazy__").Append(pnv.Name).AppendLine(" = false;") + .Append(" ").Append(propModification).Append(" override ").Append(propTypeName).Append(" ").Append(pnv.Name).AppendLine(" {"); + if (vp?.Item2 == true) + { //get 重写 + cscode.Append(" ").Append(propGetModification).Append(" get {\r\n") + .Append(cscodeExtLogic1) + .Append(" if (base.").Append(pnv.Name).Append(" == null && __lazy__").Append(pnv.Name).AppendLine(" == false) {"); + + if (nvref.Exception == null) + { + cscode.Append(" var loc2 = __fsql_orm__.Select<").Append(propElementType.DisplayCsharp()).Append(">().Where(a => ").Append(lmbdWhere).AppendLine(").ToList();") + .Append(cscodeExtLogic2) + .Append(" base.").Append(pnv.Name).Append(" = ").AppendLine(propTypeIsObservableCollection ? $"new ObservableCollection<{propElementType.DisplayCsharp()}>(loc2);" : "loc2;"); + if (refprop != null) + { + cscode.Append(" foreach (var loc1 in base.").Append(pnv.Name).AppendLine(")") + .Append(" loc1.").Append(refprop.Name).AppendLine(" = this;"); + } + cscode.Append(" __lazy__").Append(pnv.Name).AppendLine(" = true;"); + } + else + cscode.Append(" throw new Exception(\"").Append(nvref.Exception.Message.Replace("\r\n", "\\r\\n").Replace("\"", "\\\"")).AppendLine("\");"); + + cscode + .Append(" }\r\n") + .Append(" return base.").Append(pnv.Name).AppendLine(";") + .Append(" }\r\n"); + } + if (vp?.Item3 == true) + { //set 重写 + cscode.Append(" ").Append(propSetModification).Append(" set {\r\n") + .Append(" base.").Append(pnv.Name).AppendLine(" = value;") + .Append(" __lazy__").Append(pnv.Name).AppendLine(" = true;") + .Append(" }\r\n"); + } + cscode.AppendLine(" }"); + } + void LocalLazyLoadingCode(string lmbdWhere) + { + cscode.Append(" private bool __lazy__").Append(pnv.Name).AppendLine(" = false;") + .Append(" ").Append(propModification).Append(" override ").Append(propTypeName).Append(" ").Append(pnv.Name).AppendLine(" {"); + if (vp?.Item2 == true) + { //get 重写 + cscode.Append(" ").Append(propGetModification).Append(" get {\r\n") + .Append(" if (base.").Append(pnv.Name).Append(" == null && __lazy__").Append(pnv.Name).AppendLine(" == false) {"); + + if (nvref.Exception == null) + cscode.Append(" var loc3 = __fsql_orm__.Select<").Append(propTypeName).Append(">().Where(a => ").Append(lmbdWhere).AppendLine(").ToOne();") + .Append(" base.").Append(pnv.Name).AppendLine(" = loc3;") + .Append(" __lazy__").Append(pnv.Name).AppendLine(" = true;"); + else + cscode.Append(" throw new Exception(\"").Append(nvref.Exception.Message.Replace("\r\n", "\\r\\n").Replace("\"", "\\\"")).AppendLine("\");"); + + cscode + .Append(" }\r\n") + .Append(" return base.").Append(pnv.Name).AppendLine(";") + .Append(" }\r\n"); + } + if (vp?.Item3 == true) + { //set 重写 + cscode.Append(" ").Append(propSetModification).Append(" set {\r\n") + .Append(" base.").Append(pnv.Name).AppendLine(" = value;") + .Append(" __lazy__").Append(pnv.Name).AppendLine(" = true;") + .Append(" }\r\n"); + } + cscode.AppendLine(" }"); + } + #endregion + + #region [Navigate("xx", Ref = "...")] + if (pnvBind != null && pnvBindTempPrimary != null && pnvBind.Length > 0 && pnvBindTempPrimary.Length == pnvBind.Length) + { + nvref.IsTempPrimary = true; + TableInfo tbref = null; + //OneToMany + if (propElementType != null) + { + if (typeof(IEnumerable).IsAssignableFrom(pnv.PropertyType) == false) return; + tbref = propElementType == trytb.Type ? trytb : GetTableByEntity(propElementType, common); //可能是父子关系 + } + else + { + tbref = pnv.PropertyType == trytb.Type ? trytb : GetTableByEntity(pnv.PropertyType, common); //可能是父子关系 + } + + if (tbref == null) return; + var tbrefTypeName = tbref.Type.DisplayCsharp(); + Func> getBindColumns = (locTb, locBind, locFindTypeName) => + { + var locRet = new List(); + foreach (var bi in locBind) + { + if (locTb.ColumnsByCs.TryGetValue(bi, out var trybindcol) == false) + { + nvref.Exception = new Exception(CoreStrings.Navigation_ParsingError_NotFound_Property(trytbTypeName, pnv.Name, locFindTypeName, bi)); + trytb.AddOrUpdateTableRef(pnv.Name, nvref); + //if (isLazy) throw nvref.Exception; + break; + } + locRet.Add(trybindcol); + } + return locRet; + }; + + if (propElementType != null) + { + var bindColumns = getBindColumns(tbref, pnvBind, tbrefTypeName); + var bindColumnsTempPrimary = getBindColumns(trytb, pnvBindTempPrimary, trytbTypeName); + var lmbdWhere = isLazy ? new StringBuilder() : null; + + for (var a = 0; nvref.Exception == null && a < bindColumnsTempPrimary.Count; a++) + { + if (bindColumnsTempPrimary[a].CsType.NullableTypeOrThis() != bindColumns[a].CsType.NullableTypeOrThis()) + { + nvref.Exception = new Exception(CoreStrings.OneToMany_ParsingError_InconsistentType(trytbTypeName, pnv.Name, trytb.CsName, bindColumnsTempPrimary[a].CsName, tbref.CsName, bindColumns[a].CsName)); + trytb.AddOrUpdateTableRef(pnv.Name, nvref); + //if (isLazy) throw nvref.Exception; + break; + } + nvref.Columns.Add(bindColumnsTempPrimary[a]); + nvref.RefColumns.Add(bindColumns[a]); + + if (isLazy && nvref.Exception == null) + { + if (a > 0) lmbdWhere.Append(" && "); + lmbdWhere.Append("a.").Append(bindColumns[a].CsName).Append(" == this.").Append(bindColumnsTempPrimary[a].CsName); + } + } + if (nvref.Columns.Count > 0 && nvref.RefColumns.Count > 0) + { + nvref.RefEntityType = tbref.Type; + nvref.RefType = TableRefType.OneToMany; + trytb.AddOrUpdateTableRef(pnv.Name, nvref); + } + if (isLazy) LocalManyLazyLoadingCode(null, null, null, lmbdWhere.ToString()); + } + else + { + var bindColumns = getBindColumns(trytb, pnvBind, trytbTypeName); + var bindColumnsTempPrimary = getBindColumns(tbref, pnvBindTempPrimary, tbrefTypeName); + var lmbdWhere = isLazy ? new StringBuilder() : null; + + for (var a = 0; nvref.Exception == null && a < bindColumnsTempPrimary.Count; a++) + { + if (bindColumns[a].CsType.NullableTypeOrThis() != bindColumnsTempPrimary[a].CsType.NullableTypeOrThis()) + { + nvref.Exception = new Exception(CoreStrings.Navigation_ParsingError_InconsistentType(trytbTypeName, pnv.Name, trytb.CsName, bindColumns[a].CsName, tbref.CsName, bindColumnsTempPrimary[a].CsName)); + trytb.AddOrUpdateTableRef(pnv.Name, nvref); + //if (isLazy) throw nvref.Exception; + break; + } + nvref.Columns.Add(bindColumns[a]); + nvref.RefColumns.Add(bindColumnsTempPrimary[a]); + + if (isLazy && nvref.Exception == null) + { + if (a > 0) lmbdWhere.Append(" && "); + lmbdWhere.Append("a.").Append(bindColumnsTempPrimary[a].CsName).Append(" == this.").Append(bindColumns[a].CsName); + } + } + if (nvref.Columns.Count > 0 && nvref.RefColumns.Count > 0) + { + nvref.RefEntityType = tbref.Type; + nvref.RefType = TableRefType.ManyToOne; + trytb.AddOrUpdateTableRef(pnv.Name, nvref); + } + if (isLazy) LocalLazyLoadingCode(lmbdWhere.ToString()); + } + } + #endregion + if (propElementType != null) { if (typeof(IEnumerable).IsAssignableFrom(pnv.PropertyType) == false) return; @@ -780,11 +956,11 @@ namespace FreeSql.Internal TableRef trytbTf = null; try { - trytbTf = tbmid.GetTableRef(midTypePropsTrytb.Name, true); + trytbTf = tbmid.GetTableRef(midTypePropsTrytb.Name, true, false); if (trytbTf == null) { AddTableRef(common, tbmid, midTypePropsTrytb, false, null, null); - trytbTf = tbmid.GetTableRef(midTypePropsTrytb.Name, true); + trytbTf = tbmid.GetTableRef(midTypePropsTrytb.Name, true, false); } } catch (Exception ex) @@ -827,11 +1003,11 @@ namespace FreeSql.Internal TableRef tbrefTf = null; try { - tbrefTf = tbmid.GetTableRef(midTypePropsTbref.Name, true); + tbrefTf = tbmid.GetTableRef(midTypePropsTbref.Name, true, false); if (tbrefTf == null) { AddTableRef(common, tbmid, midTypePropsTbref, false, null, null); - tbrefTf = tbmid.GetTableRef(midTypePropsTbref.Name, true); + tbrefTf = tbmid.GetTableRef(midTypePropsTbref.Name, true, false); } } catch (Exception ex) @@ -1225,45 +1401,7 @@ namespace FreeSql.Internal } } - if (isLazy) - { - cscode.Append(" private bool __lazy__").Append(pnv.Name).AppendLine(" = false;") - .Append(" ").Append(propModification).Append(" override ").Append(propTypeName).Append(" ").Append(pnv.Name).AppendLine(" {"); - if (vp?.Item2 == true) - { //get 重写 - cscode.Append(" ").Append(propGetModification).Append(" get {\r\n") - .Append(cscodeExtLogic1) - .Append(" if (base.").Append(pnv.Name).Append(" == null && __lazy__").Append(pnv.Name).AppendLine(" == false) {"); - - if (nvref.Exception == null) - { - cscode.Append(" var loc2 = __fsql_orm__.Select<").Append(propElementType.DisplayCsharp()).Append(">().Where(a => ").Append(lmbdWhere.ToString()).AppendLine(").ToList();") - .Append(cscodeExtLogic2) - .Append(" base.").Append(pnv.Name).Append(" = ").AppendLine(propTypeIsObservableCollection ? $"new ObservableCollection<{propElementType.DisplayCsharp()}>(loc2);" : "loc2;"); - if (refprop != null) - { - cscode.Append(" foreach (var loc1 in base.").Append(pnv.Name).AppendLine(")") - .Append(" loc1.").Append(refprop.Name).AppendLine(" = this;"); - } - cscode.Append(" __lazy__").Append(pnv.Name).AppendLine(" = true;"); - } - else - cscode.Append(" throw new Exception(\"").Append(nvref.Exception.Message.Replace("\r\n", "\\r\\n").Replace("\"", "\\\"")).AppendLine("\");"); - - cscode - .Append(" }\r\n") - .Append(" return base.").Append(pnv.Name).AppendLine(";") - .Append(" }\r\n"); - } - if (vp?.Item3 == true) - { //set 重写 - cscode.Append(" ").Append(propSetModification).Append(" set {\r\n") - .Append(" base.").Append(pnv.Name).AppendLine(" = value;") - .Append(" __lazy__").Append(pnv.Name).AppendLine(" = true;") - .Append(" }\r\n"); - } - cscode.AppendLine(" }"); - } + if (isLazy) LocalManyLazyLoadingCode(refprop, cscodeExtLogic1, cscodeExtLogic2, lmbdWhere.ToString()); } } else @@ -1385,37 +1523,7 @@ namespace FreeSql.Internal nvref.RefType = isOnoToOne ? TableRefType.OneToOne : TableRefType.ManyToOne; trytb.AddOrUpdateTableRef(pnv.Name, nvref); } - - if (isLazy) - { - cscode.Append(" private bool __lazy__").Append(pnv.Name).AppendLine(" = false;") - .Append(" ").Append(propModification).Append(" override ").Append(propTypeName).Append(" ").Append(pnv.Name).AppendLine(" {"); - if (vp?.Item2 == true) - { //get 重写 - cscode.Append(" ").Append(propGetModification).Append(" get {\r\n") - .Append(" if (base.").Append(pnv.Name).Append(" == null && __lazy__").Append(pnv.Name).AppendLine(" == false) {"); - - if (nvref.Exception == null) - cscode.Append(" var loc3 = __fsql_orm__.Select<").Append(propTypeName).Append(">().Where(a => ").Append(lmbdWhere.ToString()).AppendLine(").ToOne();") - .Append(" base.").Append(pnv.Name).AppendLine(" = loc3;") - .Append(" __lazy__").Append(pnv.Name).AppendLine(" = true;"); - else - cscode.Append(" throw new Exception(\"").Append(nvref.Exception.Message.Replace("\r\n", "\\r\\n").Replace("\"", "\\\"")).AppendLine("\");"); - - cscode - .Append(" }\r\n") - .Append(" return base.").Append(pnv.Name).AppendLine(";") - .Append(" }\r\n"); - } - if (vp?.Item3 == true) - { //set 重写 - cscode.Append(" ").Append(propSetModification).Append(" set {\r\n") - .Append(" base.").Append(pnv.Name).AppendLine(" = value;") - .Append(" __lazy__").Append(pnv.Name).AppendLine(" = true;") - .Append(" }\r\n"); - } - cscode.AppendLine(" }"); - } + if (isLazy) LocalLazyLoadingCode(lmbdWhere.ToString()); } } static Lazy MethodLazyLoadingComplier = new Lazy(() =>