- 增加 [Navigate(xx, TempPrimary = xx)] 与非主键关联;(仅支持查询)

This commit is contained in:
2881099 2023-03-02 15:46:45 +08:00
parent c6556a47ab
commit da7bb7c74d
14 changed files with 243 additions and 101 deletions

View File

@ -377,7 +377,7 @@ namespace FreeSql
continue; continue;
} }
if (cascade == false) continue; if (cascade == false) continue;
var tbref = table.GetTableRef(prop.Name, false); var tbref = table.GetTableRef(prop.Name, false, false);
if (tbref == null) continue; if (tbref == null) continue;
var boundaryAttr = GetPropertyBoundaryAttribute(prop, boundaryName); var boundaryAttr = GetPropertyBoundaryAttribute(prop, boundaryName);
if (boundaryAttr?.Break == true) continue; if (boundaryAttr?.Break == true) continue;

View File

@ -18,7 +18,7 @@
<SignAssembly>true</SignAssembly> <SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign> <DelaySign>false</DelaySign>
<Version>1.0.6</Version> <Version>3.2.690-preview20230302</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -26,7 +26,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FreeSql.DbContext" Version="3.2.666" /> <ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext.csproj" />
</ItemGroup> </ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">

View File

@ -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.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)); 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; if (tref == null) return;
switch (tref.RefType) switch (tref.RefType)
{ {
@ -209,7 +209,7 @@ namespace FreeSql
if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return; if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return;
if (_table.ColumnsByCs.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; if (tref == null) return;
DbSet<object> refSet = null; DbSet<object> refSet = null;
switch (tref.RefType) switch (tref.RefType)

View File

@ -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.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)); 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; if (tref == null) return;
switch (tref.RefType) switch (tref.RefType)
{ {
@ -220,7 +220,7 @@ namespace FreeSql
if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return; if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return;
if (_table.ColumnsByCs.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; if (tref == null) return;
DbSet<object> refSet = null; DbSet<object> refSet = null;
switch (tref.RefType) switch (tref.RefType)

View File

@ -22,6 +22,13 @@ namespace FreeSql.DataAnnotations
/// _________________public List&lt;Topic&gt; Topics { get; set; }<para></para> /// _________________public List&lt;Topic&gt; Topics { get; set; }<para></para>
/// </summary> /// </summary>
public string Bind { get; set; } public string Bind { get; set; }
/// <summary>
/// 与非主键进行关联,仅支持 OneToMany、ManyToOne<para></para>
/// 使用方法参考 Bind 属性
/// </summary>
public string TempPrimary { get; set; }
/// <summary> /// <summary>
/// 手工绑定 ManyToMany 导航关系 /// 手工绑定 ManyToMany 导航关系
/// </summary> /// </summary>

View File

@ -60,10 +60,12 @@ namespace FreeSql.DataAnnotations
/// <param name="bind"></param> /// <param name="bind"></param>
/// <param name="manyToMany">多对多关系的中间实体类型</param> /// <param name="manyToMany">多对多关系的中间实体类型</param>
/// <returns></returns> /// <returns></returns>
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)); 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); _table._navigates.AddOrUpdate(tryProto.Name, nav, (name, old) => nav);
return this; return this;
} }
@ -148,18 +150,22 @@ namespace FreeSql.DataAnnotations
/// <param name="bind"></param> /// <param name="bind"></param>
/// <param name="manyToMany">多对多关系的中间实体类型</param> /// <param name="manyToMany">多对多关系的中间实体类型</param>
/// <returns></returns> /// <returns></returns>
public TableFluent<T> Navigate<TProto>(Expression<Func<T, TProto>> proto, string bind, Type manyToMany = null) public TableFluent<T> Navigate<TProto>(Expression<Func<T, TProto>> proto, string bind, Type manyToMany = null) => NavigateInternal(proto, bind, null, manyToMany);
public TableFluent<T> Navigate<TProto>(Expression<Func<T, TProto>> proto, string bind, string tempPrimary) => NavigateInternal(proto, bind, tempPrimary, null);
TableFluent<T> NavigateInternal<TProto>(Expression<Func<T, TProto>> proto, string bind, string tempPrimary, Type manyToMany = null)
{ {
var exp = proto?.Body; var exp = proto?.Body;
if (exp.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
var member = (exp as MemberExpression)?.Member; var member = (exp as MemberExpression)?.Member;
if (member == null) throw new FormatException(CoreStrings.Bad_Expression_Format(proto)); 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<T> Navigate(string proto, string bind, Type manyToMany = null) public TableFluent<T> Navigate(string proto, string bind, Type manyToMany = null) => NavigateInternal(proto, bind, null, manyToMany);
public TableFluent<T> Navigate(string proto, string bind, string tempPrimary) => NavigateInternal(proto, bind, tempPrimary, null);
TableFluent<T> NavigateInternal(string proto, string bind, string tempPrimary, Type manyToMany)
{ {
if (_properties.TryGetValue(proto, out var tryProto) == false) throw new KeyNotFoundException(CoreStrings.NotFound_PropertyName(proto)); 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); _table._navigates.AddOrUpdate(tryProto.Name, nav, (name, old) => nav);
return this; return this;
} }

View File

@ -409,7 +409,7 @@ public static partial class FreeSqlGlobalExtensions
#endif #endif
return list; 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))); if (tbtr == null) throw new ArgumentException(CoreStrings.ParameterError_NotValid_Navigation(nameof(property)));
var reftb = orm.CodeFirst.GetTableByEntity(t1exp.Type); var reftb = orm.CodeFirst.GetTableByEntity(t1exp.Type);
var refsel = orm.Select<object>().AsType(t1exp.Type) as Select1Provider<object>; var refsel = orm.Select<object>().AsType(t1exp.Type) as Select1Provider<object>;

View File

@ -385,6 +385,12 @@
_________________public List&lt;Topic&gt; Topics { get; set; }<para></para> _________________public List&lt;Topic&gt; Topics { get; set; }<para></para>
</summary> </summary>
</member> </member>
<member name="P:FreeSql.DataAnnotations.NavigateAttribute.TempPrimary">
<summary>
与非主键进行关联,仅支持 OneToMany、ManyToOne<para></para>
使用方法参考 Bind 属性
</summary>
</member>
<member name="P:FreeSql.DataAnnotations.NavigateAttribute.ManyToMany"> <member name="P:FreeSql.DataAnnotations.NavigateAttribute.ManyToMany">
<summary> <summary>
手工绑定 ManyToMany 导航关系 手工绑定 ManyToMany 导航关系

View File

@ -375,29 +375,29 @@ namespace FreeSql
switch (_nameConvertType) switch (_nameConvertType)
{ {
case NameConvertType.ToLower: 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.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = e.ModifyResult.Name?.ToLower();
ret.CodeFirst.IsSyncStructureToLower = true; ret.CodeFirst.IsSyncStructureToLower = true;
break; break;
case NameConvertType.ToUpper: 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.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = e.ModifyResult.Name?.ToUpper();
ret.CodeFirst.IsSyncStructureToUpper = true; ret.CodeFirst.IsSyncStructureToUpper = true;
break; break;
case NameConvertType.PascalCaseToUnderscore: 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); ret.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name);
break; break;
case NameConvertType.PascalCaseToUnderscoreWithLower: 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(); ret.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name)?.ToLower();
break; break;
case NameConvertType.PascalCaseToUnderscoreWithUpper: 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(); ret.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = PascalCaseToUnderScore(e.ModifyResult.Name)?.ToUpper();
break; break;
//case NameConvertType.UnderscoreToPascalCase: //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); // ret.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = UnderScorePascalCase(e.ModifyResult.Name);
// break; // break;
default: default:

View File

@ -1428,7 +1428,7 @@ namespace FreeSql.Internal
} }
var parm123Tb = _common.GetTableByEntity(asSelectParentExp.Type); 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 != null)
{ {
if (parm123Ref.RefType == TableRefType.PgArrayToMany) if (parm123Ref.RefType == TableRefType.PgArrayToMany)
@ -1902,7 +1902,7 @@ namespace FreeSql.Internal
{ //导航条件OneToOne、ManyToOne { //导航条件OneToOne、ManyToOne
var firstTb = tsc._tables.First().Table; var firstTb = tsc._tables.First().Table;
var parentTb = _common.GetTableByEntity(mp.Expression.Type); 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) if (parentTbRef != null)
{ {
Expression navCondExp = null; Expression navCondExp = null;
@ -2015,7 +2015,7 @@ namespace FreeSql.Internal
} }
if (tb2.ColumnsByCsIgnore.ContainsKey(mp2.Member.Name)) if (tb2.ColumnsByCsIgnore.ContainsKey(mp2.Member.Name))
throw new ArgumentException(CoreStrings.Ignored_Check_Confirm_PublicGetSet(tb2.DbName, 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.Navigation_Missing_AsSelect(tb2.DbName, mp2.Member.Name));
throw new ArgumentException(CoreStrings.NotFound_Column(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; if (select != null) return;
memberExp = tmpExp; memberExp = tmpExp;
memberTbref = exp3Tb.GetTableRef(memberExp.Member.Name, false); memberTbref = exp3Tb.GetTableRef(memberExp.Member.Name, false, true);
if (memberTbref == null) return; if (memberTbref == null) return;
switch (memberTbref.RefType) switch (memberTbref.RefType)
{ {

View File

@ -503,7 +503,7 @@ namespace FreeSql.Internal.CommonProvider
if (memExp == null) throw new ArgumentException($"{CoreStrings.Cannot_Resolve_ExpressionTree(nameof(property))}2"); if (memExp == null) throw new ArgumentException($"{CoreStrings.Cannot_Resolve_ExpressionTree(nameof(property))}2");
var parTb = _commonUtils.GetTableByEntity(memExp.Expression.Type); var parTb = _commonUtils.GetTableByEntity(memExp.Expression.Type);
if (parTb == null) throw new ArgumentException($"{CoreStrings.Cannot_Resolve_ExpressionTree(nameof(property))}3"); 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))); if (parTbref == null) throw new ArgumentException(CoreStrings.Not_Valid_Navigation_Property(nameof(property)));
switch (parTbref.RefType) switch (parTbref.RefType)
{ {
@ -682,7 +682,7 @@ namespace FreeSql.Internal.CommonProvider
var tbrefOneToManyColumns = new List<List<MemberExpression>>(); //临时 OneToMany 三个表关联,第三个表需要前两个表确定 var tbrefOneToManyColumns = new List<List<MemberExpression>>(); //临时 OneToMany 三个表关联,第三个表需要前两个表确定
if (whereExp == null) 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)); if (tbref == null) throw new Exception(CoreStrings.IncludeMany_NotValid_Navigation(tb.Type.DisplayCsharp(), collMem.Member.Name));
} }
else else

View File

@ -352,6 +352,7 @@ namespace FreeSql.Internal
if (dicConfigEntity.TryGetValue(type, out var trytb) && trytb._navigates.TryGetValue(proto.Name, out var trynav)) 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.Bind)) attr.Bind = trynav.Bind;
if (!string.IsNullOrEmpty(trynav.TempPrimary)) attr.TempPrimary = trynav.TempPrimary;
if (trynav.ManyToMany != null) attr.ManyToMany = trynav.ManyToMany; if (trynav.ManyToMany != null) attr.ManyToMany = trynav.ManyToMany;
} }
break; break;
@ -362,6 +363,7 @@ namespace FreeSql.Internal
trynav = tryattrobj as NavigateAttribute; trynav = tryattrobj as NavigateAttribute;
if (trynav == null) continue; if (trynav == null) continue;
if (!string.IsNullOrEmpty(trynav.Bind)) attr.Bind = trynav.Bind; 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; if (trynav.ManyToMany != null) attr.ManyToMany = trynav.ManyToMany;
} }
break; break;

View File

@ -38,7 +38,7 @@ namespace FreeSql.Internal.Model
{ {
_refs.AddOrUpdate(propertyName, tbref, (ok, ov) => tbref); _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 (_refs.TryGetValue(propertyName, out var tryref) == false) return null;
if (tryref.Exception != null) if (tryref.Exception != null)
@ -46,6 +46,18 @@ namespace FreeSql.Internal.Model
if (isThrowException) throw tryref.Exception; if (isThrowException) throw tryref.Exception;
return null; 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; return tryref;
} }
public IEnumerable<KeyValuePair<string, TableRef>> GetAllTableRef() => _refs; public IEnumerable<KeyValuePair<string, TableRef>> GetAllTableRef() => _refs;
@ -160,6 +172,7 @@ namespace FreeSql.Internal.Model
public List<ColumnInfo> RefColumns { get; set; } = new List<ColumnInfo>(); public List<ColumnInfo> RefColumns { get; set; } = new List<ColumnInfo>();
public Exception Exception { get; set; } public Exception Exception { get; set; }
public bool IsTempPrimary { get; set; }
} }
public enum TableRefType public enum TableRefType
{ {

View File

@ -623,12 +623,188 @@ namespace FreeSql.Internal
var pnvAttr = common.GetEntityNavigateAttribute(trytb.Type, pnv); var pnvAttr = common.GetEntityNavigateAttribute(trytb.Type, pnv);
var pnvBind = pnvAttr?.Bind?.Split(',').Select(a => a.Trim()).Where(a => !string.IsNullOrEmpty(a)).ToArray(); 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(); var nvref = new TableRef();
nvref.Property = pnv; nvref.Property = pnv;
//List 或 ICollection一对多、多对多 //List 或 ICollection一对多、多对多
var propElementType = pnv.PropertyType.GetGenericArguments().FirstOrDefault() ?? pnv.PropertyType.GetElementType(); var propElementType = pnv.PropertyType.GetGenericArguments().FirstOrDefault() ?? pnv.PropertyType.GetElementType();
var propTypeIsObservableCollection = propElementType != null && pnv.PropertyType == typeof(ObservableCollection<>).MakeGenericType(propElementType); 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<TableInfo, string[], string, List<ColumnInfo>> getBindColumns = (locTb, locBind, locFindTypeName) =>
{
var locRet = new List<ColumnInfo>();
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 (propElementType != null)
{ {
if (typeof(IEnumerable).IsAssignableFrom(pnv.PropertyType) == false) return; if (typeof(IEnumerable).IsAssignableFrom(pnv.PropertyType) == false) return;
@ -780,11 +956,11 @@ namespace FreeSql.Internal
TableRef trytbTf = null; TableRef trytbTf = null;
try try
{ {
trytbTf = tbmid.GetTableRef(midTypePropsTrytb.Name, true); trytbTf = tbmid.GetTableRef(midTypePropsTrytb.Name, true, false);
if (trytbTf == null) if (trytbTf == null)
{ {
AddTableRef(common, tbmid, midTypePropsTrytb, false, null, null); AddTableRef(common, tbmid, midTypePropsTrytb, false, null, null);
trytbTf = tbmid.GetTableRef(midTypePropsTrytb.Name, true); trytbTf = tbmid.GetTableRef(midTypePropsTrytb.Name, true, false);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -827,11 +1003,11 @@ namespace FreeSql.Internal
TableRef tbrefTf = null; TableRef tbrefTf = null;
try try
{ {
tbrefTf = tbmid.GetTableRef(midTypePropsTbref.Name, true); tbrefTf = tbmid.GetTableRef(midTypePropsTbref.Name, true, false);
if (tbrefTf == null) if (tbrefTf == null)
{ {
AddTableRef(common, tbmid, midTypePropsTbref, false, null, null); AddTableRef(common, tbmid, midTypePropsTbref, false, null, null);
tbrefTf = tbmid.GetTableRef(midTypePropsTbref.Name, true); tbrefTf = tbmid.GetTableRef(midTypePropsTbref.Name, true, false);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -1225,45 +1401,7 @@ namespace FreeSql.Internal
} }
} }
if (isLazy) if (isLazy) LocalManyLazyLoadingCode(refprop, cscodeExtLogic1, cscodeExtLogic2, lmbdWhere.ToString());
{
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(" }");
}
} }
} }
else else
@ -1385,37 +1523,7 @@ namespace FreeSql.Internal
nvref.RefType = isOnoToOne ? TableRefType.OneToOne : TableRefType.ManyToOne; nvref.RefType = isOnoToOne ? TableRefType.OneToOne : TableRefType.ManyToOne;
trytb.AddOrUpdateTableRef(pnv.Name, nvref); trytb.AddOrUpdateTableRef(pnv.Name, nvref);
} }
if (isLazy) LocalLazyLoadingCode(lmbdWhere.ToString());
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(" }");
}
} }
} }
static Lazy<MethodInfo> MethodLazyLoadingComplier = new Lazy<MethodInfo>(() => static Lazy<MethodInfo> MethodLazyLoadingComplier = new Lazy<MethodInfo>(() =>