mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	- 修改 IncludeMany ManyToMany ET 缓存的 bug;
- 完善 IncludeMany 联合键处理; - 完善 Include/IncludeMany 单元测试; - 修复 Include 延时加载 ManyToOne/OneToOne,当值为 null 时,仍然会查询一次数据;
This commit is contained in:
		@@ -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);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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) { //不读导航属性,优化单表读取性能
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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("	}");
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user