- 增加 [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

@ -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)
{

View File

@ -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<List<MemberExpression>>(); //临时 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

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 (!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;

View File

@ -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<KeyValuePair<string, TableRef>> GetAllTableRef() => _refs;
@ -160,6 +172,7 @@ namespace FreeSql.Internal.Model
public List<ColumnInfo> RefColumns { get; set; } = new List<ColumnInfo>();
public Exception Exception { get; set; }
public bool IsTempPrimary { get; set; }
}
public enum TableRefType
{

View File

@ -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<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 (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<MethodInfo> MethodLazyLoadingComplier = new Lazy<MethodInfo>(() =>