- 修改 IncludeMany ManyToMany ET 缓存的 bug;

- 完善 IncludeMany 联合键处理;
- 完善 Include/IncludeMany 单元测试;
- 修复 Include 延时加载 ManyToOne/OneToOne,当值为 null 时,仍然会查询一次数据;
This commit is contained in:
28810 2019-05-11 17:07:24 +08:00
parent c450176aec
commit dbfc33fef5
5 changed files with 190 additions and 61 deletions

View File

@ -763,7 +763,69 @@ namespace FreeSql.Tests.Sqlite {
} }
[Fact] [Fact]
public void Include_OneToChilds() { public void Include_OneToChilds() {
var tag1 = new Tag {
Ddd = DateTime.Now.Second,
Name = "test_oneToChilds_01_中国"
};
tag1.Id = (int)g.sqlite.Insert(tag1).ExecuteIdentity();
var tag1_1 = new Tag {
Parent_id = tag1.Id,
Ddd = DateTime.Now.Second,
Name = "test_oneToChilds_01_北京"
};
tag1_1.Id = (int)g.sqlite.Insert(tag1_1).ExecuteIdentity();
var tag1_2 = new Tag {
Parent_id = tag1.Id,
Ddd = DateTime.Now.Second,
Name = "test_oneToChilds_01_上海"
};
tag1_2.Id = (int)g.sqlite.Insert(tag1_2).ExecuteIdentity();
var tag2 = new Tag {
Ddd = DateTime.Now.Second,
Name = "test_oneToChilds_02_美国"
};
tag2.Id = (int)g.sqlite.Insert(tag2).ExecuteIdentity();
var tag2_1 = new Tag {
Parent_id = tag2.Id,
Ddd = DateTime.Now.Second,
Name = "test_oneToChilds_02_纽约"
};
tag2_1.Id = (int)g.sqlite.Insert(tag2_1).ExecuteIdentity();
var tag2_2 = new Tag {
Parent_id = tag2.Id,
Ddd = DateTime.Now.Second,
Name = "test_oneToChilds_02_华盛顿"
};
tag2_2.Id = (int)g.sqlite.Insert(tag2_2).ExecuteIdentity();
var tags0 = g.sqlite.Select<Tag>()
.Include(a => a.Parent)
.Where(a => a.Id == tag1.Id || a.Id == tag2.Id)
.ToList();
var tags = g.sqlite.Select<Tag>()
.IncludeMany(a => a.Tags)
.Include(a => a.Parent)
.IncludeMany(a => a.Songs)
.Where(a => a.Id == tag1.Id || a.Id == tag2.Id)
.ToList();
var tags2 = g.sqlite.Select<Tag>()
.IncludeMany(a => a.Tags,
then => then.Include(a => a.Parent).IncludeMany(a => a.Songs))
.Include(a => a.Parent)
.IncludeMany(a => a.Songs)
.Where(a => a.Id == tag1.Id || a.Id == tag2.Id)
.ToList();
var tags3 = g.sqlite.Select<Tag>()
.IncludeMany(a => a.Tags,
then => then.Include(a => a.Parent).IncludeMany(a => a.Songs).IncludeMany(a => a.Tags))
.Include(a => a.Parent)
.IncludeMany(a => a.Songs)
.Where(a => a.Id == tag1.Id || a.Id == tag2.Id)
.ToList();
} }
[Fact] [Fact]
@ -813,7 +875,22 @@ namespace FreeSql.Tests.Sqlite {
var songs = g.sqlite.Select<Song>() var songs = g.sqlite.Select<Song>()
.IncludeMany(a => a.Tags) .IncludeMany(a => a.Tags)
.Where(a => a.Id == song1.Id || a.Id == song2.Id || a.Id == song3.Id)
.ToList(); .ToList();
Assert.Equal(3, songs.Count);
Assert.Equal(2, songs[0].Tags.Count);
Assert.Equal(1, songs[1].Tags.Count);
Assert.Equal(3, songs[2].Tags.Count);
var songs2 = g.sqlite.Select<Song>()
.IncludeMany(a => a.Tags,
then => then.IncludeMany(t => t.Songs))
.Where(a => a.Id == song1.Id || a.Id == song2.Id || a.Id == song3.Id)
.ToList();
Assert.Equal(3, songs2.Count);
Assert.Equal(2, songs2[0].Tags.Count);
Assert.Equal(1, songs2[1].Tags.Count);
Assert.Equal(3, songs2[2].Tags.Count);
} }
} }
} }

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<Version>0.5.13</Version> <Version>0.5.14</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>YeXiangQin</Authors> <Authors>YeXiangQin</Authors>
<Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description> <Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description>

View File

@ -286,8 +286,6 @@ namespace FreeSql.Internal.CommonProvider {
var after = new Aop.CurdAfterEventArgs(before, exception, ret); var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfter?.Invoke(this, after); _orm.Aop.CurdAfter?.Invoke(this, after);
} }
_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
_trackToList?.Invoke(ret);
return ret; return ret;
}); });
} }
@ -315,13 +313,18 @@ namespace FreeSql.Internal.CommonProvider {
var after = new Aop.CurdAfterEventArgs(before, exception, ret); var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfter?.Invoke(this, after); _orm.Aop.CurdAfter?.Invoke(this, after);
} }
_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
_trackToList?.Invoke(ret);
return ret; return ret;
}); });
} }
internal List<T1> ToListPrivate(GetAllFieldExpressionTreeInfo af, (ReadAnonymousTypeInfo, List<object>)[] otherData) { internal List<T1> ToListPrivate(GetAllFieldExpressionTreeInfo af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData) {
var sql = this.ToSql(af.Field); string sql = null;
if (otherData?.Length > 0) {
var sbField = new StringBuilder().Append(af.Field);
foreach (var other in otherData)
sbField.Append(other.field);
sql = this.ToSql(sbField.ToString());
} else
sql = this.ToSql(af.Field);
if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = $"{sql}{string.Join("|", _params.Select(a => a.Value))}"; if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = $"{sql}{string.Join("|", _params.Select(a => a.Value))}";
return _orm.Cache.Shell(_cache.key, _cache.seconds, () => { return _orm.Cache.Shell(_cache.key, _cache.seconds, () => {
@ -336,7 +339,7 @@ namespace FreeSql.Internal.CommonProvider {
if (otherData != null) { if (otherData != null) {
var idx = af.FieldCount - 1; var idx = af.FieldCount - 1;
foreach (var other in otherData) foreach (var other in otherData)
other.Item2.Add(_commonExpression.ReadAnonymous(other.Item1, dr, ref idx, false)); other.retlist.Add(_commonExpression.ReadAnonymous(other.read, dr, ref idx, false));
} }
}, CommandType.Text, sql, dbParms); }, CommandType.Text, sql, dbParms);
} catch (Exception ex) { } catch (Exception ex) {
@ -352,8 +355,15 @@ namespace FreeSql.Internal.CommonProvider {
return ret; return ret;
}); });
} }
async internal Task<List<T1>> ToListPrivateAsync(GetAllFieldExpressionTreeInfo af, (ReadAnonymousTypeInfo, List<object>)[] otherData) { async internal Task<List<T1>> ToListPrivateAsync(GetAllFieldExpressionTreeInfo af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData) {
var sql = this.ToSql(af.Field); string sql = null;
if (otherData?.Length > 0) {
var sbField = new StringBuilder().Append(af.Field);
foreach (var other in otherData)
sbField.Append(other.field);
sql = this.ToSql(sbField.ToString());
} else
sql = this.ToSql(af.Field);
if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = $"{sql}{string.Join("|", _params.Select(a => a.Value))}"; if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = $"{sql}{string.Join("|", _params.Select(a => a.Value))}";
return await _orm.Cache.ShellAsync(_cache.key, _cache.seconds, async () => { return await _orm.Cache.ShellAsync(_cache.key, _cache.seconds, async () => {
@ -368,7 +378,7 @@ namespace FreeSql.Internal.CommonProvider {
if (otherData != null) { if (otherData != null) {
var idx = af.FieldCount - 1; var idx = af.FieldCount - 1;
foreach (var other in otherData) foreach (var other in otherData)
other.Item2.Add(_commonExpression.ReadAnonymous(other.Item1, dr, ref idx, false)); other.retlist.Add(_commonExpression.ReadAnonymous(other.read, dr, ref idx, false));
} }
return Task.CompletedTask; return Task.CompletedTask;
}, CommandType.Text, sql, dbParms); }, CommandType.Text, sql, dbParms);
@ -501,13 +511,30 @@ namespace FreeSql.Internal.CommonProvider {
var tb = _tables.First(); var tb = _tables.First();
var index = 0; var index = 0;
var tborder = new[] { tb }.Concat(_tables.ToArray().Where((a, b) => b > 0).OrderBy(a => a.Alias));
var tbiindex = 0; var tbiindex = 0;
foreach (var tbi in _tables.ToArray().OrderBy(a => a.Alias)) { foreach (var tbi in tborder) {
if (tbiindex > 0 && tbi.Type == SelectTableInfoType.From) continue; if (tbiindex > 0 && tbi.Type == SelectTableInfoType.From) continue;
if (tbiindex > 0 && tbi.Alias.StartsWith($"{tb.Alias}__") == false) continue; if (tbiindex > 0 && tbi.Alias.StartsWith($"{tb.Alias}__") == false) continue;
var typei = tbi.Table.TypeLazy ?? tbi.Table.Type; var typei = tbi.Table.TypeLazy ?? tbi.Table.Type;
Expression curExp = retExp; Expression curExp = retExp;
var colidx = 0;
foreach (var col in tbi.Table.Columns.Values) {
if (index > 0) {
field.Append(", ");
if (tbiindex > 0 && colidx == 0) field.Append("\r\n");
}
var quoteName = _commonUtils.QuoteSqlName(col.Attribute.Name);
field.Append(_commonUtils.QuoteReadColumn(col.Attribute.MapType, $"{tbi.Alias}.{quoteName}"));
++index;
if (dicfield.ContainsKey(quoteName)) field.Append(" as").Append(index);
else dicfield.Add(quoteName, true);
++colidx;
}
tbiindex++;
if (tbiindex == 0) if (tbiindex == 0)
blockExp.AddRange(new Expression[] { blockExp.AddRange(new Expression[] {
Expression.Assign(readExp, Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(typei), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp, Expression.Constant(_commonUtils) })), Expression.Assign(readExp, Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(typei), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp, Expression.Constant(_commonUtils) })),
@ -547,7 +574,7 @@ namespace FreeSql.Internal.CommonProvider {
if (iscontinue) continue; if (iscontinue) continue;
blockExp.Add( blockExp.Add(
Expression.IfThen( Expression.IfThenElse(
curExpIfNotNull, curExpIfNotNull,
Expression.Block(new Expression[] { Expression.Block(new Expression[] {
Expression.Assign(readExp, Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(typei), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp, Expression.Constant(_commonUtils) })), Expression.Assign(readExp, Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(typei), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp, Expression.Constant(_commonUtils) })),
@ -555,11 +582,16 @@ namespace FreeSql.Internal.CommonProvider {
Expression.GreaterThan(readExpDataIndex, dataIndexExp), Expression.GreaterThan(readExpDataIndex, dataIndexExp),
Expression.Assign(dataIndexExp, readExpDataIndex) Expression.Assign(dataIndexExp, readExpDataIndex)
), ),
Expression.IfThen( Expression.IfThenElse(
Expression.NotEqual(readExpValue, Expression.Constant(null)), Expression.NotEqual(readExpValue, Expression.Constant(null)),
Expression.Assign(curExp, Expression.Convert(readExpValue, typei)) Expression.Assign(curExp, Expression.Convert(readExpValue, typei)),
Expression.Assign(curExp, Expression.Constant(null, typei))
) )
}) }),
Expression.Block(
Expression.Assign(readExpValue, Expression.Constant(null, typeof(object))),
Expression.Assign(dataIndexExp, Expression.Constant(index))
)
) )
); );
} }
@ -571,21 +603,6 @@ namespace FreeSql.Internal.CommonProvider {
Expression.Call(Expression.TypeAs(readExpValue, typei), tbi.Table.TypeLazySetOrm, ormExp) Expression.Call(Expression.TypeAs(readExpValue, typei), tbi.Table.TypeLazySetOrm, ormExp)
) )
); //将 orm 传递给 lazy ); //将 orm 传递给 lazy
var colidx = 0;
foreach (var col in tbi.Table.Columns.Values) {
if (index > 0) {
field.Append(", ");
if (tbiindex > 0 && colidx == 0) field.Append("\r\n");
}
var quoteName = _commonUtils.QuoteSqlName(col.Attribute.Name);
field.Append(_commonUtils.QuoteReadColumn(col.Attribute.MapType, $"{tbi.Alias}.{quoteName}"));
++index;
if (dicfield.ContainsKey(quoteName)) field.Append(" as").Append(index);
else dicfield.Add(quoteName, true);
++colidx;
}
tbiindex++;
} }
blockExp.AddRange(new Expression[] { blockExp.AddRange(new Expression[] {
@ -685,9 +702,17 @@ namespace FreeSql.Internal.CommonProvider {
Expression.IfThen(Expression.GreaterThan(readExpDataIndex, dataIndexExp), Expression.IfThen(Expression.GreaterThan(readExpDataIndex, dataIndexExp),
Expression.Assign(dataIndexExp, readExpDataIndex)), Expression.Assign(dataIndexExp, readExpDataIndex)),
//Expression.Call(typeof(Trace).GetMethod("WriteLine", new Type[]{typeof(string)}), Expression.Call(typeof(string).GetMethod("Concat", new Type[]{typeof(object) }), readExpValue)), //Expression.Call(typeof(Trace).GetMethod("WriteLine", new Type[]{typeof(string)}), Expression.Call(typeof(string).GetMethod("Concat", new Type[]{typeof(object) }), readExpValue)),
Expression.IfThen(Expression.NotEqual(readExpValue, Expression.Constant(null)),
//Expression.Call(retExp, propGetSetMethod, Expression.Default(prop.PropertyType)), tb1.TypeLazy != null ?
Expression.Call(retExp, propGetSetMethod, Expression.Convert(readExpValue, prop.PropertyType))) Expression.IfThenElse(
Expression.NotEqual(readExpValue, Expression.Constant(null)),
Expression.Call(retExp, propGetSetMethod, Expression.Convert(readExpValue, prop.PropertyType)),
Expression.Call(retExp, propGetSetMethod, Expression.Convert(Utils.GetDataReaderValueBlockExpression(prop.PropertyType, Expression.Constant(null)), prop.PropertyType))
) :
Expression.IfThen(
Expression.NotEqual(readExpValue, Expression.Constant(null)),
Expression.Call(retExp, propGetSetMethod, Expression.Convert(readExpValue, prop.PropertyType))
)
}); });
} }
if (otherindex == 0) { //不读导航属性,优化单表读取性能 if (otherindex == 0) { //不读导航属性,优化单表读取性能

View File

@ -343,13 +343,15 @@ namespace FreeSql.Internal.CommonProvider {
if (collMem.Expression.NodeType != ExpressionType.Parameter) if (collMem.Expression.NodeType != ExpressionType.Parameter)
_commonExpression.ExpressionWhereLambda(_tables, Expression.MakeMemberAccess(collMem.Expression, tb.Properties[tb.ColumnsByCs.First().Value.CsName]), null); _commonExpression.ExpressionWhereLambda(_tables, Expression.MakeMemberAccess(collMem.Expression, tb.Properties[tb.ColumnsByCs.First().Value.CsName]), null);
var tbref = tb.GetTableRef(collMem.Member.Name, true);
_includeToList.Enqueue(listObj => { _includeToList.Enqueue(listObj => {
var list = listObj as List<T1>; var list = listObj as List<T1>;
if (list == null) return; if (list == null) return;
if (list.Any() == false) return; if (list.Any() == false) return;
var tbref = tb.GetTableRef(collMem.Member.Name, true);
if (tbref.Columns.Any() == false) return;
var t1parm = Expression.Parameter(typeof(T1)); var t1parm = Expression.Parameter(typeof(T1));
Expression membersExp = t1parm; Expression membersExp = t1parm;
while (members.Any()) membersExp = Expression.MakeMemberAccess(membersExp, members.Pop()); while (members.Any()) membersExp = Expression.MakeMemberAccess(membersExp, members.Pop());
@ -381,7 +383,7 @@ namespace FreeSql.Internal.CommonProvider {
if (true) { if (true) {
var tbref2 = _commonUtils.GetTableByEntity(tbref.RefEntityType); var tbref2 = _commonUtils.GetTableByEntity(tbref.RefEntityType);
if (tbref.Columns.Count == 1) { if (tbref.Columns.Count == 1) {
var arrExp = Expression.NewArrayInit(tbref.Columns[0].CsType, list.Select(a => Expression.Constant(Convert.ChangeType(getListValue(a, tbref.Columns[0].CsName), tbref.Columns[0].CsType))).ToArray()); var arrExp = Expression.NewArrayInit(tbref.Columns[0].CsType, list.Select(a => Expression.Constant(Convert.ChangeType(getListValue(a, tbref.Columns[0].CsName), tbref.Columns[0].CsType))).Distinct().ToArray());
var otmExpParm1 = Expression.Parameter(typeof(TNavigate), "a"); var otmExpParm1 = Expression.Parameter(typeof(TNavigate), "a");
var containsMethod = _dicTypeMethod.GetOrAdd(tbref.Columns[0].CsType, et => new ConcurrentDictionary<string, MethodInfo>()).GetOrAdd("Contains", mn => var containsMethod = _dicTypeMethod.GetOrAdd(tbref.Columns[0].CsType, et => new ConcurrentDictionary<string, MethodInfo>()).GetOrAdd("Contains", mn =>
typeof(Enumerable).GetMethods().Where(a => a.Name == mn).First()).MakeGenericMethod(tbref.Columns[0].CsType); typeof(Enumerable).GetMethods().Where(a => a.Name == mn).First()).MakeGenericMethod(tbref.Columns[0].CsType);
@ -466,21 +468,34 @@ namespace FreeSql.Internal.CommonProvider {
if (true) { if (true) {
var tbref2 = _commonUtils.GetTableByEntity(tbref.RefEntityType); var tbref2 = _commonUtils.GetTableByEntity(tbref.RefEntityType);
var tbrefMid = _commonUtils.GetTableByEntity(tbref.RefMiddleEntityType); var tbrefMid = _commonUtils.GetTableByEntity(tbref.RefMiddleEntityType);
var sbJoin = new StringBuilder().Append($"{_commonUtils.QuoteSqlName(tbrefMid.DbName)} midtb ON");
for (var z = 0; z < tbref.RefColumns.Count; z++) {
if (z > 0) sbJoin.Append(" AND");
sbJoin.Append($" midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[tbref.Columns.Count + z].Attribute.Name)} = a.{_commonUtils.QuoteSqlName(tbref.RefColumns[z].Attribute.Name)}");
}
subSelect.InnerJoin(sbJoin.ToString());
sbJoin.Clear();
if (tbref.Columns.Count == 1) { if (tbref.Columns.Count == 1) {
//var midParmExp = Expression.Parameter(tbref.RefMiddleEntityType, "midtb"); subSelect.Where(_commonUtils.FormatSql($"midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[0].Attribute.Name)} in {{0}}", list.Select(a => getListValue(a, tbref.Columns[0].CsName)).Distinct()));
//(subSelect as Select1Provider<TNavigate>)._tables.Add(new SelectTableInfo {
// Alias = "midtb",
// AliasInit = "midtb",
// On = $"{_commonUtils.QuoteSqlName(tbrefMid.DbName)} midtb ON midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[1].Attribute.Name)} = a.{_commonUtils.QuoteSqlName(tbref.RefColumns[0].Attribute.Name)}",
// Parameter = midParmExp,
// Table = tbrefMid,
// Type = SelectTableInfoType.InnerJoin
//});
subSelect.InnerJoin($"{_commonUtils.QuoteSqlName(tbrefMid.DbName)} midtb ON midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[1].Attribute.Name)} = a.{_commonUtils.QuoteSqlName(tbref.RefColumns[0].Attribute.Name)}");
subSelect.Where(_commonUtils.FormatSql($"midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[0].Attribute.Name)} in {{0}}", list.Select(a => getListValue(a, tbref.Columns[0].CsName))));
} else { } else {
Dictionary<string, bool> sbDic = new Dictionary<string, bool>();
for (var y = 0; y < list.Count; y++) {
var sbWhereOne = new StringBuilder();
sbWhereOne.Append(" (");
for (var z = 0; z < tbref.Columns.Count; z++) {
if (z > 0) sbWhereOne.Append(" AND");
sbWhereOne.Append(_commonUtils.FormatSql($" midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[z].Attribute.Name)}={{0}}", getListValue(list[y], tbref.Columns[z].CsName)));
}
sbWhereOne.Append(")");
var whereOne = sbWhereOne.ToString();
sbWhereOne.Clear();
if (sbDic.ContainsKey(whereOne) == false) sbDic.Add(whereOne, true);
}
var sbWhere = new StringBuilder();
foreach (var sbd in sbDic)
sbWhere.Append(" OR").Append(sbd.Key);
subSelect.Where(sbWhere.Remove(0, 3).ToString());
sbWhere.Clear();
} }
then?.Invoke(subSelect); then?.Invoke(subSelect);
@ -490,7 +505,7 @@ namespace FreeSql.Internal.CommonProvider {
var subSelectP1 = (subSelect as Select1Provider<TNavigate>); var subSelectP1 = (subSelect as Select1Provider<TNavigate>);
var af = subSelectP1.GetAllFieldExpressionTreeLevelAll(); var af = subSelectP1.GetAllFieldExpressionTreeLevelAll();
if (_selectExpression == null) {// return this.InternalToList<T1>(_selectExpression).Select(a => (a, ()).ToList(); if (_selectExpression == null) {// return this.InternalToList<T1>(_selectExpression).Select(a => (a, ()).ToList();
var sb = new StringBuilder().Append(af.Field); var field = new StringBuilder();
var read = new ReadAnonymousTypeInfo(); var read = new ReadAnonymousTypeInfo();
read.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties; read.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties;
read.Consturctor = tbrefMid.TypeLazy.GetConstructor(new Type[0]); read.Consturctor = tbrefMid.TypeLazy.GetConstructor(new Type[0]);
@ -505,10 +520,9 @@ namespace FreeSql.Internal.CommonProvider {
Property = tbrefMid.Properties[col.CsName] Property = tbrefMid.Properties[col.CsName]
}; };
read.Childs.Add(child); read.Childs.Add(child);
sb.Append(", ").Append(_commonUtils.QuoteReadColumn(child.MapType, child.DbField)); field.Append(", ").Append(_commonUtils.QuoteReadColumn(child.MapType, child.DbField));
} }
af.Field = sb.ToString(); subList = subSelectP1.ToListPrivate(af, new[] { (field.ToString(), read, midList) });
subList = subSelectP1.ToListPrivate(af, new[] { (read, midList) });
} else } else
subList = subSelectP1.ToListPrivate(af, null); subList = subSelectP1.ToListPrivate(af, null);
@ -518,17 +532,25 @@ namespace FreeSql.Internal.CommonProvider {
return; return;
} }
Dictionary<string, Tuple<T1, List<TNavigate>>> dicList = new Dictionary<string, Tuple<T1, List<TNavigate>>>(); Dictionary<string, List<Tuple<T1, List<TNavigate>>>> dicList = new Dictionary<string, List<Tuple<T1, List<TNavigate>>>>();
foreach (var item in list) { foreach (var item in list) {
if (tbref.Columns.Count == 1) { if (tbref.Columns.Count == 1) {
dicList.Add(getListValue(item, tbref.Columns[0].CsName).ToString(), Tuple.Create(item, new List<TNavigate>())); var dicListKey = getListValue(item, tbref.Columns[0].CsName).ToString();
var dicListVal = Tuple.Create(item, new List<TNavigate>());
if (dicList.TryGetValue(dicListKey, out var items) == false)
dicList.Add(dicListKey, items = new List<Tuple<T1, List<TNavigate>>>());
items.Add(dicListVal);
} else { } else {
var sb = new StringBuilder(); var sb = new StringBuilder();
for (var z = 0; z < tbref.Columns.Count; z++) { for (var z = 0; z < tbref.Columns.Count; z++) {
if (z > 0) sb.Append("*$*"); if (z > 0) sb.Append("*$*");
sb.Append(getListValue(item, tbref.Columns[z].CsName)); sb.Append(getListValue(item, tbref.Columns[z].CsName));
} }
dicList.Add(sb.Remove(0, 3).ToString(), Tuple.Create(item, new List<TNavigate>())); var dicListKey = sb.Remove(0, 3).ToString();
var dicListVal = Tuple.Create(item, new List<TNavigate>());
if (dicList.TryGetValue(dicListKey, out var items) == false)
dicList.Add(dicListKey, items = new List<Tuple<T1, List<TNavigate>>>());
items.Add(dicListVal);
sb.Clear(); sb.Clear();
} }
} }
@ -545,11 +567,13 @@ namespace FreeSql.Internal.CommonProvider {
key = sb.ToString(); key = sb.ToString();
sb.Clear(); sb.Clear();
} }
if (dicList.TryGetValue(key, out var t1item) == false) return; if (dicList.TryGetValue(key, out var t1items) == false) return;
t1item.Item2.Add(subList[a]); foreach (var t1item in t1items)
t1item.Item2.Add(subList[a]);
} }
foreach (var t1item in dicList.Values) foreach (var t1items in dicList.Values)
setListValue(t1item.Item1, t1item.Item2); foreach (var t1item in t1items)
setListValue(t1item.Item1, t1item.Item2);
dicList.Clear(); dicList.Clear();
} }
break; break;

View File

@ -605,7 +605,10 @@ namespace FreeSql.Internal {
.Append(" }\r\n"); .Append(" }\r\n");
} }
if (vp.Item3) { //set 重写 if (vp.Item3) { //set 重写
cscode.Append(" set => base.").Append(pnv.Name).AppendLine(" = value;"); cscode.Append(" set {\r\n")
.Append(" base.").Append(pnv.Name).AppendLine(" = value;")
.Append(" __lazy__").Append(pnv.Name).AppendLine(" = true;")
.Append(" }\r\n");
} }
cscode.AppendLine(" }"); cscode.AppendLine(" }");
} }