mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	Include 贪婪加载第一版,已通过集合的导航数据加载,包括 OneToMany/ManyToMany
This commit is contained in:
		@@ -7,7 +7,7 @@
 | 
				
			|||||||
	</PropertyGroup>
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
		<PackageReference Include="FreeSql.DbContext" Version="0.5.8" />
 | 
							<PackageReference Include="FreeSql.DbContext" Version="0.5.12.1" />
 | 
				
			||||||
		<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.8" />
 | 
							<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.8" />
 | 
				
			||||||
		<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
 | 
							<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
 | 
				
			||||||
		<PackageReference Include="xunit" Version="2.4.0" />
 | 
							<PackageReference Include="xunit" Version="2.4.0" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -756,5 +756,64 @@ namespace FreeSql.Tests.Sqlite {
 | 
				
			|||||||
			sql = query.ToSql().Replace("\r\n", "");
 | 
								sql = query.ToSql().Replace("\r\n", "");
 | 
				
			||||||
			Assert.Equal("SELECT a.\"Id\", a.\"Clicks\", a.\"TypeGuid\", a.\"Title\", a.\"CreateTime\" FROM \"tb_topic22AsTable1\" a LEFT JOIN \"TestTypeInfo\" b on b.\"Guid\" = a.\"TypeGuid\" and b.\"Name\" = @bname", sql);
 | 
								Assert.Equal("SELECT a.\"Id\", a.\"Clicks\", a.\"TypeGuid\", a.\"Title\", a.\"CreateTime\" FROM \"tb_topic22AsTable1\" a LEFT JOIN \"TestTypeInfo\" b on b.\"Guid\" = a.\"TypeGuid\" and b.\"Name\" = @bname", sql);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[Fact]
 | 
				
			||||||
 | 
							public void Include_OneToMany() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							[Fact]
 | 
				
			||||||
 | 
							public void Include_OneToChilds() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[Fact]
 | 
				
			||||||
 | 
							public void Include_ManyToMany() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var tag1 = new Tag {
 | 
				
			||||||
 | 
									Ddd = DateTime.Now.Second,
 | 
				
			||||||
 | 
									Name = "test_manytoMany_01_中国"
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								tag1.Id = (int)g.sqlite.Insert(tag1).ExecuteIdentity();
 | 
				
			||||||
 | 
								var tag2 = new Tag {
 | 
				
			||||||
 | 
									Ddd = DateTime.Now.Second,
 | 
				
			||||||
 | 
									Name = "test_manytoMany_02_美国"
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								tag2.Id = (int)g.sqlite.Insert(tag2).ExecuteIdentity();
 | 
				
			||||||
 | 
								var tag3 = new Tag {
 | 
				
			||||||
 | 
									Ddd = DateTime.Now.Second,
 | 
				
			||||||
 | 
									Name = "test_manytoMany_03_日本"
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								tag3.Id = (int)g.sqlite.Insert(tag3).ExecuteIdentity();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var song1 = new Song {
 | 
				
			||||||
 | 
									Create_time = DateTime.Now,
 | 
				
			||||||
 | 
									Title = "test_manytoMany_01_我是中国人.mp3",
 | 
				
			||||||
 | 
									Url = "http://ww.baidu.com/"
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								song1.Id = (int)g.sqlite.Insert(song1).ExecuteIdentity();
 | 
				
			||||||
 | 
								var song2 = new Song {
 | 
				
			||||||
 | 
									Create_time = DateTime.Now,
 | 
				
			||||||
 | 
									Title = "test_manytoMany_02_爱你一万年.mp3",
 | 
				
			||||||
 | 
									Url = "http://ww.163.com/"
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								song2.Id = (int)g.sqlite.Insert(song2).ExecuteIdentity();
 | 
				
			||||||
 | 
								var song3 = new Song {
 | 
				
			||||||
 | 
									Create_time = DateTime.Now,
 | 
				
			||||||
 | 
									Title = "test_manytoMany_03_千年等一回.mp3",
 | 
				
			||||||
 | 
									Url = "http://ww.sina.com/"
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								song3.Id = (int)g.sqlite.Insert(song3).ExecuteIdentity();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								g.sqlite.Insert(new Song_tag { Song_id = song1.Id, Tag_id = tag1.Id }).ExecuteAffrows();
 | 
				
			||||||
 | 
								g.sqlite.Insert(new Song_tag { Song_id = song2.Id, Tag_id = tag1.Id }).ExecuteAffrows();
 | 
				
			||||||
 | 
								g.sqlite.Insert(new Song_tag { Song_id = song3.Id, Tag_id = tag1.Id }).ExecuteAffrows();
 | 
				
			||||||
 | 
								g.sqlite.Insert(new Song_tag { Song_id = song1.Id, Tag_id = tag2.Id }).ExecuteAffrows();
 | 
				
			||||||
 | 
								g.sqlite.Insert(new Song_tag { Song_id = song3.Id, Tag_id = tag2.Id }).ExecuteAffrows();
 | 
				
			||||||
 | 
								g.sqlite.Insert(new Song_tag { Song_id = song3.Id, Tag_id = tag3.Id }).ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var songs = g.sqlite.Select<Song>()
 | 
				
			||||||
 | 
									.IncludeMany(a => a.Tags)
 | 
				
			||||||
 | 
									.ToList();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -94,6 +94,8 @@ namespace FreeSql.Tests {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			public ICollection<Model2> Childs { get; set; }
 | 
								public ICollection<Model2> Childs { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public int M2Id { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public class Model2 {
 | 
							public class Model2 {
 | 
				
			||||||
@@ -110,6 +112,32 @@ namespace FreeSql.Tests {
 | 
				
			|||||||
		[Fact]
 | 
							[Fact]
 | 
				
			||||||
		public void Test1() {
 | 
							public void Test1() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								g.sqlite.GetRepository<Model1, int>().Insert(new Model1 {
 | 
				
			||||||
 | 
									title = "test_" + DateTime.Now.ToString("yyyyMMddHHmmss"),
 | 
				
			||||||
 | 
									M2Id = DateTime.Now.Second + DateTime.Now.Minute,
 | 
				
			||||||
 | 
									Childs = new[] {
 | 
				
			||||||
 | 
										new Model2 {
 | 
				
			||||||
 | 
											 title = "model2Test_title_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "0001",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										new Model2 {
 | 
				
			||||||
 | 
											 title = "model2Test_title_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "0002",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										new Model2 {
 | 
				
			||||||
 | 
											 title = "model2Test_title_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "0003",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										new Model2 {
 | 
				
			||||||
 | 
											 title = "model2Test_title_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "0004",
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var includet1 = g.sqlite.Select<Model1>()
 | 
				
			||||||
 | 
									.IncludeMany(a => a.Childs, s => s.Where(a => a.id > 0))
 | 
				
			||||||
 | 
									.Where(a => a.id > 10)
 | 
				
			||||||
 | 
									.ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var ttt1 = g.sqlite.Select<Model1>().Where(a => a.Childs.AsSelect().Any(b => b.title == "111")).ToList();
 | 
								var ttt1 = g.sqlite.Select<Model1>().Where(a => a.Childs.AsSelect().Any(b => b.title == "111")).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -602,15 +602,28 @@ namespace FreeSql.Extensions.EntityUtil {
 | 
				
			|||||||
					});
 | 
										});
 | 
				
			||||||
					if (_table.Properties.ContainsKey(pn)) {
 | 
										if (_table.Properties.ContainsKey(pn)) {
 | 
				
			||||||
						var prop = _table.Properties[pn];
 | 
											var prop = _table.Properties[pn];
 | 
				
			||||||
						exps.Add(
 | 
					
 | 
				
			||||||
							Expression.Assign(
 | 
											if (_table.ColumnsByCs.ContainsKey(pn)) {
 | 
				
			||||||
								Expression.MakeMemberAccess(var1Parm, prop),
 | 
												exps.Add(
 | 
				
			||||||
								Expression.Convert(
 | 
													Expression.Assign(
 | 
				
			||||||
									FreeSql.Internal.Utils.GetDataReaderValueBlockExpression(prop.PropertyType, parm3),
 | 
														Expression.MakeMemberAccess(var1Parm, prop),
 | 
				
			||||||
									prop.PropertyType
 | 
														Expression.Convert(
 | 
				
			||||||
 | 
															FreeSql.Internal.Utils.GetDataReaderValueBlockExpression(prop.PropertyType, parm3),
 | 
				
			||||||
 | 
															prop.PropertyType
 | 
				
			||||||
 | 
														)
 | 
				
			||||||
								)
 | 
													)
 | 
				
			||||||
							)
 | 
												);
 | 
				
			||||||
						);
 | 
											} else {
 | 
				
			||||||
 | 
												exps.Add(
 | 
				
			||||||
 | 
													Expression.Assign(
 | 
				
			||||||
 | 
														Expression.MakeMemberAccess(var1Parm, prop),
 | 
				
			||||||
 | 
														Expression.Convert(
 | 
				
			||||||
 | 
															parm3,
 | 
				
			||||||
 | 
															prop.PropertyType
 | 
				
			||||||
 | 
														)
 | 
				
			||||||
 | 
													)
 | 
				
			||||||
 | 
												);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					return Expression.Lambda<Action<object, string, object>>(Expression.Block(new[] { var1Parm }, exps), new[] { parm1, parm2, parm3 }).Compile();
 | 
										return Expression.Lambda<Action<object, string, object>>(Expression.Block(new[] { var1Parm }, exps), new[] { parm1, parm2, parm3 }).Compile();
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1263,6 +1263,23 @@
 | 
				
			|||||||
            <param name="column">列</param>
 | 
					            <param name="column">列</param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.ISelect`1.Include``1(System.Linq.Expressions.Expression{System.Func{`0,``0}})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            贪婪加载导航属性,如果查询中已经使用了 a.Parent.Parent 类似表达式,则可以无需此操作
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="TNavigate"></typeparam>
 | 
				
			||||||
 | 
					            <param name="navigateSelector">选择一个导航属性</param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.ISelect`1.IncludeMany``1(System.Linq.Expressions.Expression{System.Func{`0,System.Collections.Generic.ICollection{``0}}},System.Action{FreeSql.ISelect{``0}})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            贪婪加载集合的导航属性,其实是分两次查询,ToList 后进行了数据重装
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="TNavigate"></typeparam>
 | 
				
			||||||
 | 
					            <param name="navigateSelector">选择一个集合的导航属性</param>
 | 
				
			||||||
 | 
					            <param name="then">即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?)</param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.ISelectFromExpression`1.Where(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
 | 
					        <member name="M:FreeSql.ISelectFromExpression`1.Where(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com")
 | 
					            查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -293,5 +293,21 @@ namespace FreeSql {
 | 
				
			|||||||
		/// <param name="column">列</param>
 | 
							/// <param name="column">列</param>
 | 
				
			||||||
		/// <returns></returns>
 | 
							/// <returns></returns>
 | 
				
			||||||
		ISelect<T1> OrderByDescending<TMember>(Expression<Func<T1, TMember>> column);
 | 
							ISelect<T1> OrderByDescending<TMember>(Expression<Func<T1, TMember>> column);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/// <summary>
 | 
				
			||||||
 | 
							/// 贪婪加载导航属性,如果查询中已经使用了 a.Parent.Parent 类似表达式,则可以无需此操作
 | 
				
			||||||
 | 
							/// </summary>
 | 
				
			||||||
 | 
							/// <typeparam name="TNavigate"></typeparam>
 | 
				
			||||||
 | 
							/// <param name="navigateSelector">选择一个导航属性</param>
 | 
				
			||||||
 | 
							/// <returns></returns>
 | 
				
			||||||
 | 
							ISelect<T1> Include<TNavigate>(Expression<Func<T1, TNavigate>> navigateSelector) where TNavigate : class;
 | 
				
			||||||
 | 
							/// <summary>
 | 
				
			||||||
 | 
							/// 贪婪加载集合的导航属性,其实是分两次查询,ToList 后进行了数据重装
 | 
				
			||||||
 | 
							/// </summary>
 | 
				
			||||||
 | 
							/// <typeparam name="TNavigate"></typeparam>
 | 
				
			||||||
 | 
							/// <param name="navigateSelector">选择一个集合的导航属性</param>
 | 
				
			||||||
 | 
							/// <param name="then">即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?)</param>
 | 
				
			||||||
 | 
							/// <returns></returns>
 | 
				
			||||||
 | 
							ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, ICollection<TNavigate>>> navigateSelector, Action<ISelect<TNavigate>> then = null) where TNavigate : class;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -330,7 +330,7 @@ namespace FreeSql.Internal {
 | 
				
			|||||||
		static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectWhereMethodInfo = new ConcurrentDictionary<Type, MethodInfo>();
 | 
							static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectWhereMethodInfo = new ConcurrentDictionary<Type, MethodInfo>();
 | 
				
			||||||
		static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectWhereSqlMethodInfo = new ConcurrentDictionary<Type, MethodInfo>();
 | 
							static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectWhereSqlMethodInfo = new ConcurrentDictionary<Type, MethodInfo>();
 | 
				
			||||||
		static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectAnyMethodInfo = new ConcurrentDictionary<Type, MethodInfo>();
 | 
							static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectAnyMethodInfo = new ConcurrentDictionary<Type, MethodInfo>();
 | 
				
			||||||
		static ConcurrentDictionary<Type, PropertyInfo> _dicNullableValueProperty = new ConcurrentDictionary<Type, PropertyInfo>();
 | 
							internal static ConcurrentDictionary<Type, PropertyInfo> _dicNullableValueProperty = new ConcurrentDictionary<Type, PropertyInfo>();
 | 
				
			||||||
		static ConcurrentDictionary<Type, Expression> _dicFreeSqlGlobalExtensionsAsSelectExpression = new ConcurrentDictionary<Type, Expression>();
 | 
							static ConcurrentDictionary<Type, Expression> _dicFreeSqlGlobalExtensionsAsSelectExpression = new ConcurrentDictionary<Type, Expression>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal string ExpressionBinary(string oper, Expression leftExp, Expression rightExp, ExpTSC tsc) {
 | 
							internal string ExpressionBinary(string oper, Expression leftExp, Expression rightExp, ExpTSC tsc) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
		protected DbTransaction _transaction;
 | 
							protected DbTransaction _transaction;
 | 
				
			||||||
		protected DbConnection _connection;
 | 
							protected DbConnection _connection;
 | 
				
			||||||
		protected Action<object> _trackToList;
 | 
							protected Action<object> _trackToList;
 | 
				
			||||||
 | 
							protected Queue<Action<object>> _includeToList = new Queue<Action<object>>();
 | 
				
			||||||
		protected bool _distinct;
 | 
							protected bool _distinct;
 | 
				
			||||||
		protected Expression _selectExpression;
 | 
							protected Expression _selectExpression;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,6 +70,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			toType.GetField("_transaction", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._transaction);
 | 
								toType.GetField("_transaction", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._transaction);
 | 
				
			||||||
			toType.GetField("_connection", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._connection);
 | 
								toType.GetField("_connection", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._connection);
 | 
				
			||||||
			toType.GetField("_trackToList", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._trackToList);
 | 
								toType.GetField("_trackToList", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._trackToList);
 | 
				
			||||||
 | 
								toType.GetField("_includeToList", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._includeToList);
 | 
				
			||||||
			toType.GetField("_distinct", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._distinct);
 | 
								toType.GetField("_distinct", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._distinct);
 | 
				
			||||||
			toType.GetField("_selectExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._selectExpression);
 | 
								toType.GetField("_selectExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._selectExpression);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -318,7 +320,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
				return ret;
 | 
									return ret;
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		List<T1> ToListPrivate(GetAllFieldExpressionTreeInfo af) {
 | 
							internal List<T1> ToListPrivate(GetAllFieldExpressionTreeInfo af, (ReadAnonymousTypeInfo, List<object>)[] otherData) {
 | 
				
			||||||
			var sql = this.ToSql(af.Field);
 | 
								var 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))}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -331,6 +333,11 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
				try {
 | 
									try {
 | 
				
			||||||
					_orm.Ado.ExecuteReader(_connection, _transaction, dr => {
 | 
										_orm.Ado.ExecuteReader(_connection, _transaction, dr => {
 | 
				
			||||||
						ret.Add(af.Read(_orm, dr));
 | 
											ret.Add(af.Read(_orm, dr));
 | 
				
			||||||
 | 
											if (otherData != null) {
 | 
				
			||||||
 | 
												var idx = af.FieldCount - 1;
 | 
				
			||||||
 | 
												foreach (var other in otherData)
 | 
				
			||||||
 | 
													other.Item2.Add(_commonExpression.ReadAnonymous(other.Item1, dr, ref idx, false));
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
					}, CommandType.Text, sql, dbParms);
 | 
										}, CommandType.Text, sql, dbParms);
 | 
				
			||||||
				} catch (Exception ex) {
 | 
									} catch (Exception ex) {
 | 
				
			||||||
					exception = ex;
 | 
										exception = ex;
 | 
				
			||||||
@@ -339,12 +346,13 @@ 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);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									while (_includeToList.Any()) _includeToList.Dequeue()?.Invoke(ret);
 | 
				
			||||||
				_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
									_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
				
			||||||
				_trackToList?.Invoke(ret);
 | 
									_trackToList?.Invoke(ret);
 | 
				
			||||||
				return ret;
 | 
									return ret;
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		async Task<List<T1>> ToListPrivateAsync(GetAllFieldExpressionTreeInfo af) {
 | 
							async internal Task<List<T1>> ToListPrivateAsync(GetAllFieldExpressionTreeInfo af, (ReadAnonymousTypeInfo, List<object>)[] otherData) {
 | 
				
			||||||
			var sql = this.ToSql(af.Field);
 | 
								var 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))}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -357,6 +365,11 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
				try {
 | 
									try {
 | 
				
			||||||
					await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, dr => {
 | 
										await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, dr => {
 | 
				
			||||||
						ret.Add(af.Read(_orm, dr));
 | 
											ret.Add(af.Read(_orm, dr));
 | 
				
			||||||
 | 
											if (otherData != null) {
 | 
				
			||||||
 | 
												var idx = af.FieldCount - 1;
 | 
				
			||||||
 | 
												foreach (var other in otherData)
 | 
				
			||||||
 | 
													other.Item2.Add(_commonExpression.ReadAnonymous(other.Item1, dr, ref idx, false));
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
						return Task.CompletedTask;
 | 
											return Task.CompletedTask;
 | 
				
			||||||
					}, CommandType.Text, sql, dbParms);
 | 
										}, CommandType.Text, sql, dbParms);
 | 
				
			||||||
				} catch (Exception ex) {
 | 
									} catch (Exception ex) {
 | 
				
			||||||
@@ -366,6 +379,7 @@ 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);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									while (_includeToList.Any()) _includeToList.Dequeue()?.Invoke(ret);
 | 
				
			||||||
				_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
									_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
				
			||||||
				_trackToList?.Invoke(ret);
 | 
									_trackToList?.Invoke(ret);
 | 
				
			||||||
				return ret;
 | 
									return ret;
 | 
				
			||||||
@@ -373,11 +387,11 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		public List<T1> ToList(bool includeNestedMembers = false) {
 | 
							public List<T1> ToList(bool includeNestedMembers = false) {
 | 
				
			||||||
			if (_selectExpression != null) return this.InternalToList<T1>(_selectExpression);
 | 
								if (_selectExpression != null) return this.InternalToList<T1>(_selectExpression);
 | 
				
			||||||
			return this.ToListPrivate(includeNestedMembers == false ? this.GetAllFieldExpressionTreeLevel2() : this.GetAllFieldExpressionTreeLevelAll());
 | 
								return this.ToListPrivate(includeNestedMembers == false ? this.GetAllFieldExpressionTreeLevel2() : this.GetAllFieldExpressionTreeLevelAll(), null);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		public Task<List<T1>> ToListAsync(bool includeNestedMembers = false) {
 | 
							public Task<List<T1>> ToListAsync(bool includeNestedMembers = false) {
 | 
				
			||||||
			if (_selectExpression != null) return this.InternalToListAsync<T1>(_selectExpression);
 | 
								if (_selectExpression != null) return this.InternalToListAsync<T1>(_selectExpression);
 | 
				
			||||||
			return this.ToListPrivateAsync(includeNestedMembers == false ? this.GetAllFieldExpressionTreeLevel2() : this.GetAllFieldExpressionTreeLevelAll());
 | 
								return this.ToListPrivateAsync(includeNestedMembers == false ? this.GetAllFieldExpressionTreeLevel2() : this.GetAllFieldExpressionTreeLevelAll(), null);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		public T1 ToOne() {
 | 
							public T1 ToOne() {
 | 
				
			||||||
			this.Limit(1);
 | 
								this.Limit(1);
 | 
				
			||||||
@@ -460,6 +474,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
		static ConcurrentDictionary<string, GetAllFieldExpressionTreeInfo> _dicGetAllFieldExpressionTree = new ConcurrentDictionary<string, GetAllFieldExpressionTreeInfo>();
 | 
							static ConcurrentDictionary<string, GetAllFieldExpressionTreeInfo> _dicGetAllFieldExpressionTree = new ConcurrentDictionary<string, GetAllFieldExpressionTreeInfo>();
 | 
				
			||||||
		public class GetAllFieldExpressionTreeInfo {
 | 
							public class GetAllFieldExpressionTreeInfo {
 | 
				
			||||||
			public string Field { get; set; }
 | 
								public string Field { get; set; }
 | 
				
			||||||
 | 
								public int FieldCount { get; set; }
 | 
				
			||||||
			public Func<IFreeSql, DbDataReader, T1> Read { get; set; }
 | 
								public Func<IFreeSql, DbDataReader, T1> Read { get; set; }
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		protected GetAllFieldExpressionTreeInfo GetAllFieldExpressionTreeLevelAll() {
 | 
							protected GetAllFieldExpressionTreeInfo GetAllFieldExpressionTreeLevelAll() {
 | 
				
			||||||
@@ -579,6 +594,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
				});
 | 
									});
 | 
				
			||||||
				return new GetAllFieldExpressionTreeInfo {
 | 
									return new GetAllFieldExpressionTreeInfo {
 | 
				
			||||||
					Field = field.ToString(),
 | 
										Field = field.ToString(),
 | 
				
			||||||
 | 
										FieldCount = index,
 | 
				
			||||||
					Read = Expression.Lambda<Func<IFreeSql, DbDataReader, T1>>(Expression.Block(new[] { retExp, dataIndexExp, readExp }, blockExp), new[] { ormExp, rowExp }).Compile()
 | 
										Read = Expression.Lambda<Func<IFreeSql, DbDataReader, T1>>(Expression.Block(new[] { retExp, dataIndexExp, readExp }, blockExp), new[] { ormExp, rowExp }).Compile()
 | 
				
			||||||
				};
 | 
									};
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,14 @@
 | 
				
			|||||||
using FreeSql.Internal.Model;
 | 
					using FreeSql.Extensions.EntityUtil;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Reflection;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
using System.Text.RegularExpressions;
 | 
					using System.Text.RegularExpressions;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
@@ -64,7 +69,6 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			_tables[0].Parameter = column.Parameters[0];
 | 
								_tables[0].Parameter = column.Parameters[0];
 | 
				
			||||||
			return this.InternalAvg<TMember>(column?.Body);
 | 
								return this.InternalAvg<TMember>(column?.Body);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public Task<TMember> AvgAsync<TMember>(Expression<Func<T1, TMember>> column) {
 | 
							public Task<TMember> AvgAsync<TMember>(Expression<Func<T1, TMember>> column) {
 | 
				
			||||||
			if (column == null) return Task.FromResult(default(TMember));
 | 
								if (column == null) return Task.FromResult(default(TMember));
 | 
				
			||||||
			_tables[0].Parameter = column.Parameters[0];
 | 
								_tables[0].Parameter = column.Parameters[0];
 | 
				
			||||||
@@ -73,19 +77,12 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		public abstract ISelect<T1, T2> From<T2>(Expression<Func<ISelectFromExpression<T1>, T2, ISelectFromExpression<T1>>> exp) where T2 : class;// { this.InternalFrom(exp?.Body); var ret = new Select3Provider<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
							public abstract ISelect<T1, T2> From<T2>(Expression<Func<ISelectFromExpression<T1>, T2, ISelectFromExpression<T1>>> exp) where T2 : class;// { this.InternalFrom(exp?.Body); var ret = new Select3Provider<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
		public abstract ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class;// { this.InternalFrom(exp?.Body); var ret = new Select3Provider<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
							public abstract ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class;// { this.InternalFrom(exp?.Body); var ret = new Select3Provider<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public abstract ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class;// { this.InternalFrom(exp?.Body); var ret = new Select4Provider<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
							public abstract ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class;// { this.InternalFrom(exp?.Body); var ret = new Select4Provider<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public abstract ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class;// { this.InternalFrom(exp?.Body); var ret = new Select5Provider<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
							public abstract ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class;// { this.InternalFrom(exp?.Body); var ret = new Select5Provider<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public abstract ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class;// { this.InternalFrom(exp?.Body); var ret = new Select6Provider<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
							public abstract ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class;// { this.InternalFrom(exp?.Body); var ret = new Select6Provider<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public abstract ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class;// { this.InternalFrom(exp?.Body); var ret = new Select7Provider<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
							public abstract ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class;// { this.InternalFrom(exp?.Body); var ret = new Select7Provider<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class;// { this.InternalFrom(exp?.Body); var ret = new Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
							public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class;// { this.InternalFrom(exp?.Body); var ret = new Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class;// { this.InternalFrom(exp?.Body); var ret = new Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
							public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class;// { this.InternalFrom(exp?.Body); var ret = new Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class;// { this.InternalFrom(exp?.Body); var ret = new Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
							public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class;// { this.InternalFrom(exp?.Body); var ret = new Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public ISelectGrouping<TKey, T1> GroupBy<TKey>(Expression<Func<T1, TKey>> columns) {
 | 
							public ISelectGrouping<TKey, T1> GroupBy<TKey>(Expression<Func<T1, TKey>> columns) {
 | 
				
			||||||
@@ -99,7 +96,6 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			_tables[0].Parameter = column.Parameters[0];
 | 
								_tables[0].Parameter = column.Parameters[0];
 | 
				
			||||||
			return this.InternalMax<TMember>(column?.Body);
 | 
								return this.InternalMax<TMember>(column?.Body);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public Task<TMember> MaxAsync<TMember>(Expression<Func<T1, TMember>> column) {
 | 
							public Task<TMember> MaxAsync<TMember>(Expression<Func<T1, TMember>> column) {
 | 
				
			||||||
			if (column == null) return Task.FromResult(default(TMember));
 | 
								if (column == null) return Task.FromResult(default(TMember));
 | 
				
			||||||
			_tables[0].Parameter = column.Parameters[0];
 | 
								_tables[0].Parameter = column.Parameters[0];
 | 
				
			||||||
@@ -111,7 +107,6 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			_tables[0].Parameter = column.Parameters[0];
 | 
								_tables[0].Parameter = column.Parameters[0];
 | 
				
			||||||
			return this.InternalMin<TMember>(column?.Body);
 | 
								return this.InternalMin<TMember>(column?.Body);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public Task<TMember> MinAsync<TMember>(Expression<Func<T1, TMember>> column) {
 | 
							public Task<TMember> MinAsync<TMember>(Expression<Func<T1, TMember>> column) {
 | 
				
			||||||
			if (column == null) return Task.FromResult(default(TMember));
 | 
								if (column == null) return Task.FromResult(default(TMember));
 | 
				
			||||||
			_tables[0].Parameter = column.Parameters[0];
 | 
								_tables[0].Parameter = column.Parameters[0];
 | 
				
			||||||
@@ -123,7 +118,6 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			_tables[0].Parameter = column.Parameters[0];
 | 
								_tables[0].Parameter = column.Parameters[0];
 | 
				
			||||||
			return this.InternalOrderBy(column?.Body);
 | 
								return this.InternalOrderBy(column?.Body);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public ISelect<T1> OrderByDescending<TMember>(Expression<Func<T1, TMember>> column) {
 | 
							public ISelect<T1> OrderByDescending<TMember>(Expression<Func<T1, TMember>> column) {
 | 
				
			||||||
			if (column == null) return this;
 | 
								if (column == null) return this;
 | 
				
			||||||
			_tables[0].Parameter = column.Parameters[0];
 | 
								_tables[0].Parameter = column.Parameters[0];
 | 
				
			||||||
@@ -135,7 +129,6 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			_tables[0].Parameter = column.Parameters[0];
 | 
								_tables[0].Parameter = column.Parameters[0];
 | 
				
			||||||
			return this.InternalSum<TMember>(column?.Body);
 | 
								return this.InternalSum<TMember>(column?.Body);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public Task<TMember> SumAsync<TMember>(Expression<Func<T1, TMember>> column) {
 | 
							public Task<TMember> SumAsync<TMember>(Expression<Func<T1, TMember>> column) {
 | 
				
			||||||
			if (column == null) return Task.FromResult(default(TMember));
 | 
								if (column == null) return Task.FromResult(default(TMember));
 | 
				
			||||||
			_tables[0].Parameter = column.Parameters[0];
 | 
								_tables[0].Parameter = column.Parameters[0];
 | 
				
			||||||
@@ -152,8 +145,8 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			_tables[0].Parameter = select.Parameters[0];
 | 
								_tables[0].Parameter = select.Parameters[0];
 | 
				
			||||||
			return this.InternalToListAsync<TReturn>(select?.Body);
 | 
								return this.InternalToListAsync<TReturn>(select?.Body);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		List<TDto> ISelect<T1>.ToList<TDto>() => ToList(GetToListDtoSelector<TDto>());
 | 
							public List<TDto> ToList<TDto>() => ToList(GetToListDtoSelector<TDto>());
 | 
				
			||||||
		Task<List<TDto>> ISelect<T1>.ToListAsync<TDto>() => ToListAsync(GetToListDtoSelector<TDto>());
 | 
							public Task<List<TDto>> ToListAsync<TDto>() => ToListAsync(GetToListDtoSelector<TDto>());
 | 
				
			||||||
		Expression<Func<T1, TDto>> GetToListDtoSelector<TDto>() {
 | 
							Expression<Func<T1, TDto>> GetToListDtoSelector<TDto>() {
 | 
				
			||||||
			var ctor = typeof(TDto).GetConstructor(new Type[0]);
 | 
								var ctor = typeof(TDto).GetConstructor(new Type[0]);
 | 
				
			||||||
			return Expression.Lambda<Func<T1, TDto>>(Expression.New(ctor),
 | 
								return Expression.Lambda<Func<T1, TDto>>(Expression.New(ctor),
 | 
				
			||||||
@@ -310,5 +303,259 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
		public TReturn First<TReturn>(Expression<Func<T1, TReturn>> select) => this.ToOne(select);
 | 
							public TReturn First<TReturn>(Expression<Func<T1, TReturn>> select) => this.ToOne(select);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public Task<TReturn> FirstAsync<TReturn>(Expression<Func<T1, TReturn>> select) => this.ToOneAsync(select);
 | 
							public Task<TReturn> FirstAsync<TReturn>(Expression<Func<T1, TReturn>> select) => this.ToOneAsync(select);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public ISelect<T1> Include<TNavigate>(Expression<Func<T1, TNavigate>> navigateSelector) where TNavigate : class {
 | 
				
			||||||
 | 
								var expBody = navigateSelector?.Body;
 | 
				
			||||||
 | 
								if (expBody == null) return this;
 | 
				
			||||||
 | 
								var tb = _commonUtils.GetTableByEntity(expBody.Type);
 | 
				
			||||||
 | 
								if (tb == null) throw new Exception("Include 参数类型错误");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								_commonExpression.ExpressionWhereLambda(_tables, Expression.MakeMemberAccess(expBody, tb.Properties[tb.ColumnsByCs.First().Value.CsName]), null);
 | 
				
			||||||
 | 
								return this;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							static MethodInfo GetEntityValueWithPropertyNameMethod = typeof(EntityUtilExtensions).GetMethod("GetEntityValueWithPropertyName");
 | 
				
			||||||
 | 
							static ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>> _dicTypeMethod = new ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>>();
 | 
				
			||||||
 | 
							public ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, ICollection<TNavigate>>> navigateSelector, Action<ISelect<TNavigate>> then = null) where TNavigate : class {
 | 
				
			||||||
 | 
								var expBody = navigateSelector?.Body;
 | 
				
			||||||
 | 
								if (expBody == null) return this;
 | 
				
			||||||
 | 
								if (expBody.NodeType != ExpressionType.MemberAccess) throw new Exception("IncludeMany 参数1 类型错误,表达式类型应该为 MemberAccess");
 | 
				
			||||||
 | 
								var collMem = expBody as MemberExpression;
 | 
				
			||||||
 | 
								Expression tmpExp = collMem.Expression;
 | 
				
			||||||
 | 
								var members = new Stack<MemberInfo>();
 | 
				
			||||||
 | 
								var isbreak = false;
 | 
				
			||||||
 | 
								while(isbreak == false) {
 | 
				
			||||||
 | 
									switch (tmpExp.NodeType) {
 | 
				
			||||||
 | 
										case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
											var memExp = tmpExp as MemberExpression;
 | 
				
			||||||
 | 
											tmpExp = memExp.Expression;
 | 
				
			||||||
 | 
											members.Push(memExp.Member);
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
										case ExpressionType.Parameter:
 | 
				
			||||||
 | 
											isbreak = true;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										default:
 | 
				
			||||||
 | 
											throw new Exception("IncludeMany 参数1 类型错误");
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								var tb = _commonUtils.GetTableByEntity(collMem.Expression.Type);
 | 
				
			||||||
 | 
								if (tb == null) throw new Exception("IncludeMany 参数1 类型错误");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (collMem.Expression.NodeType != ExpressionType.Parameter)
 | 
				
			||||||
 | 
									_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 => {
 | 
				
			||||||
 | 
									var list = listObj as List<T1>;
 | 
				
			||||||
 | 
									if (list == null) return;
 | 
				
			||||||
 | 
									if (list.Any() == false) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									var t1parm = Expression.Parameter(typeof(T1));
 | 
				
			||||||
 | 
									Expression membersExp = t1parm;
 | 
				
			||||||
 | 
									while (members.Any()) membersExp = Expression.MakeMemberAccess(membersExp, members.Pop());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									var listValueExp = Expression.Parameter(typeof(List<TNavigate>), "listValue");
 | 
				
			||||||
 | 
									var setListValue = Expression.Lambda<Action<T1, List<TNavigate>>>(
 | 
				
			||||||
 | 
										Expression.Assign(
 | 
				
			||||||
 | 
											Expression.MakeMemberAccess(membersExp, collMem.Member),
 | 
				
			||||||
 | 
											Expression.TypeAs(listValueExp, collMem.Type)
 | 
				
			||||||
 | 
										), t1parm, listValueExp).Compile();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									var returnTarget = Expression.Label(typeof(object));
 | 
				
			||||||
 | 
									var propertyNameExp = Expression.Parameter(typeof(string), "propertyName");
 | 
				
			||||||
 | 
									var getListValue = Expression.Lambda<Func<T1, string, object>>(
 | 
				
			||||||
 | 
										Expression.Block(
 | 
				
			||||||
 | 
											Expression.Return(returnTarget, Expression.Call(null, GetEntityValueWithPropertyNameMethod, Expression.Constant(_orm), Expression.Constant(membersExp.Type), membersExp, propertyNameExp)),
 | 
				
			||||||
 | 
											Expression.Label(returnTarget, Expression.Default(typeof(object)))
 | 
				
			||||||
 | 
										), t1parm, propertyNameExp).Compile();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									foreach (var item in list) {
 | 
				
			||||||
 | 
										setListValue(item, null);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									var subSelect = _orm.Select<TNavigate>().WithConnection(_connection).WithTransaction(_transaction).TrackToList(_trackToList);
 | 
				
			||||||
 | 
									if (_tableRules?.Any() == true)
 | 
				
			||||||
 | 
										foreach (var tr in _tableRules) subSelect.AsTable(tr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									switch (tbref.RefType) {
 | 
				
			||||||
 | 
										case TableRefType.OneToMany:
 | 
				
			||||||
 | 
											if (true) {
 | 
				
			||||||
 | 
												var tbref2 = _commonUtils.GetTableByEntity(tbref.RefEntityType);
 | 
				
			||||||
 | 
												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 otmExpParm1 = Expression.Parameter(typeof(TNavigate), "a");
 | 
				
			||||||
 | 
													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);
 | 
				
			||||||
 | 
													var refCol = Expression.MakeMemberAccess(otmExpParm1, tbref2.Properties[tbref.RefColumns[0].CsName]);
 | 
				
			||||||
 | 
													if (refCol.Type.IsNullableType()) refCol = Expression.Property(refCol, CommonExpression._dicNullableValueProperty.GetOrAdd(refCol.Type, ct1 => ct1.GetProperty("Value")));
 | 
				
			||||||
 | 
													subSelect.Where(Expression.Lambda<Func<TNavigate, bool>>(
 | 
				
			||||||
 | 
														Expression.Call(null, containsMethod, arrExp, refCol), otmExpParm1));
 | 
				
			||||||
 | 
												} else {
 | 
				
			||||||
 | 
													var otmExpParm1 = Expression.Parameter(typeof(TNavigate), "a");
 | 
				
			||||||
 | 
													Expression expOr = null;
 | 
				
			||||||
 | 
													foreach (var item in list) {
 | 
				
			||||||
 | 
														Expression expAnd = null;
 | 
				
			||||||
 | 
														for (var z = 0; z < tbref.Columns.Count; z++) {
 | 
				
			||||||
 | 
															var colVal = getListValue(item, tbref.Columns[z].CsName);
 | 
				
			||||||
 | 
															var expTmp = Expression.Equal(Expression.MakeMemberAccess(otmExpParm1, tbref2.Properties[tbref.RefColumns[0].CsName]), Expression.Constant(colVal));
 | 
				
			||||||
 | 
															if (z == 0) expAnd = expTmp;
 | 
				
			||||||
 | 
															else expAnd = Expression.AndAlso(expAnd, expTmp);
 | 
				
			||||||
 | 
														}
 | 
				
			||||||
 | 
														if (expOr == null) expOr = expAnd;
 | 
				
			||||||
 | 
														else expOr = Expression.OrElse(expOr, expAnd);
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
													subSelect.Where(Expression.Lambda<Func<TNavigate, bool>>(expOr, otmExpParm1));
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												then?.Invoke(subSelect);
 | 
				
			||||||
 | 
												var subList = subSelect.ToList(true);
 | 
				
			||||||
 | 
												if (subList.Any() == false) {
 | 
				
			||||||
 | 
													foreach (var item in list)
 | 
				
			||||||
 | 
														setListValue(item, new List<TNavigate>());
 | 
				
			||||||
 | 
													return;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												Dictionary<string, Tuple<T1, List<TNavigate>>> dicList = new Dictionary<string, Tuple<T1, List<TNavigate>>>();
 | 
				
			||||||
 | 
												foreach (var item in list) {
 | 
				
			||||||
 | 
													if (tbref.Columns.Count == 1) {
 | 
				
			||||||
 | 
														dicList.Add(getListValue(item, tbref.Columns[0].CsName).ToString(), Tuple.Create(item, new List<TNavigate>()));
 | 
				
			||||||
 | 
													} else {
 | 
				
			||||||
 | 
														var sb = new StringBuilder();
 | 
				
			||||||
 | 
														for (var z = 0; z < tbref.Columns.Count; z++) {
 | 
				
			||||||
 | 
															if (z > 0) sb.Append("*$*");
 | 
				
			||||||
 | 
															sb.Append(getListValue(item, tbref.Columns[z].CsName));
 | 
				
			||||||
 | 
														}
 | 
				
			||||||
 | 
														dicList.Add(sb.Remove(0, 3).ToString(), Tuple.Create(item, new List<TNavigate>()));
 | 
				
			||||||
 | 
														sb.Clear();
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												var parentNavs = new List<string>();
 | 
				
			||||||
 | 
												foreach (var navProp in tbref2.Properties) {
 | 
				
			||||||
 | 
													if (tbref2.ColumnsByCs.ContainsKey(navProp.Key)) continue;
 | 
				
			||||||
 | 
													if (tbref2.ColumnsByCsIgnore.ContainsKey(navProp.Key)) continue;
 | 
				
			||||||
 | 
													var tr2ref = tbref2.GetTableRef(navProp.Key, false);
 | 
				
			||||||
 | 
													if (tr2ref == null) continue;
 | 
				
			||||||
 | 
													if (tr2ref.RefType != TableRefType.ManyToOne) continue;
 | 
				
			||||||
 | 
													if (tr2ref.RefEntityType != tb.Type) continue;
 | 
				
			||||||
 | 
													parentNavs.Add(navProp.Key);
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												foreach (var nav in subList) {
 | 
				
			||||||
 | 
													string key = null;
 | 
				
			||||||
 | 
													if (tbref.RefColumns.Count == 1) {
 | 
				
			||||||
 | 
														key = _orm.GetEntityValueWithPropertyName(tbref.RefEntityType, nav, tbref.RefColumns[0].CsName).ToString();
 | 
				
			||||||
 | 
													} else {
 | 
				
			||||||
 | 
														var sb = new StringBuilder();
 | 
				
			||||||
 | 
														for (var z = 0; z < tbref.RefColumns.Count; z++) {
 | 
				
			||||||
 | 
															if (z > 0) sb.Append("*$*");
 | 
				
			||||||
 | 
															sb.Append(_orm.GetEntityValueWithPropertyName(tbref.RefEntityType, nav, tbref.RefColumns[z].CsName));
 | 
				
			||||||
 | 
														}
 | 
				
			||||||
 | 
														key = sb.ToString();
 | 
				
			||||||
 | 
														sb.Clear();
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
													if (dicList.TryGetValue(key, out var t1item) == false) return;
 | 
				
			||||||
 | 
													t1item.Item2.Add(nav);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
													//将子集合的,多对一,对象设置为当前对象
 | 
				
			||||||
 | 
													foreach (var parentNav in parentNavs)
 | 
				
			||||||
 | 
														_orm.SetEntityValueWithPropertyName(tbref.RefMiddleEntityType, nav, parentNav, t1item.Item1);
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												foreach (var t1item in dicList.Values)
 | 
				
			||||||
 | 
													setListValue(t1item.Item1, t1item.Item2);
 | 
				
			||||||
 | 
												dicList.Clear();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										case TableRefType.ManyToMany:
 | 
				
			||||||
 | 
											if (true) {
 | 
				
			||||||
 | 
												var tbref2 = _commonUtils.GetTableByEntity(tbref.RefEntityType);
 | 
				
			||||||
 | 
												var tbrefMid = _commonUtils.GetTableByEntity(tbref.RefMiddleEntityType);
 | 
				
			||||||
 | 
												if (tbref.Columns.Count == 1) {
 | 
				
			||||||
 | 
													//var midParmExp = Expression.Parameter(tbref.RefMiddleEntityType, "midtb");
 | 
				
			||||||
 | 
													//(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 {
 | 
				
			||||||
 | 
													
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												then?.Invoke(subSelect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												List<TNavigate> subList = null;
 | 
				
			||||||
 | 
												List<object> midList = new List<object>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												var subSelectP1 = (subSelect as Select1Provider<TNavigate>);
 | 
				
			||||||
 | 
												var af = subSelectP1.GetAllFieldExpressionTreeLevelAll();
 | 
				
			||||||
 | 
												if (_selectExpression == null) {// return this.InternalToList<T1>(_selectExpression).Select(a => (a, ()).ToList();
 | 
				
			||||||
 | 
													var sb = new StringBuilder().Append(af.Field);
 | 
				
			||||||
 | 
													var read = new ReadAnonymousTypeInfo();
 | 
				
			||||||
 | 
													read.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties;
 | 
				
			||||||
 | 
													read.Consturctor = tbrefMid.TypeLazy.GetConstructor(new Type[0]);
 | 
				
			||||||
 | 
													read.Table = tbrefMid;
 | 
				
			||||||
 | 
													foreach (var col in tbrefMid.Columns.Values) {
 | 
				
			||||||
 | 
														if (tbref.MiddleColumns.Where(a => a.CsName == col.CsName).Any() == false) continue;
 | 
				
			||||||
 | 
														var child = new ReadAnonymousTypeInfo {
 | 
				
			||||||
 | 
															CsName = col.CsName,
 | 
				
			||||||
 | 
															CsType = col.CsType,
 | 
				
			||||||
 | 
															DbField = $"midtb.{_commonUtils.QuoteSqlName(col.Attribute.Name)}",
 | 
				
			||||||
 | 
															MapType = col.Attribute.MapType,
 | 
				
			||||||
 | 
															Property = tbrefMid.Properties[col.CsName]
 | 
				
			||||||
 | 
														};
 | 
				
			||||||
 | 
														read.Childs.Add(child);
 | 
				
			||||||
 | 
														sb.Append(", ").Append(_commonUtils.QuoteReadColumn(child.MapType, child.DbField));
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
													af.Field = sb.ToString();
 | 
				
			||||||
 | 
													subList = subSelectP1.ToListPrivate(af, new[] { (read, midList) });
 | 
				
			||||||
 | 
												} else
 | 
				
			||||||
 | 
													subList = subSelectP1.ToListPrivate(af, null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												if (subList.Any() == false) {
 | 
				
			||||||
 | 
													foreach (var item in list)
 | 
				
			||||||
 | 
														setListValue(item, new List<TNavigate>());
 | 
				
			||||||
 | 
													return;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												Dictionary<string, Tuple<T1, List<TNavigate>>> dicList = new Dictionary<string, Tuple<T1, List<TNavigate>>>();
 | 
				
			||||||
 | 
												foreach (var item in list) {
 | 
				
			||||||
 | 
													if (tbref.Columns.Count == 1) {
 | 
				
			||||||
 | 
														dicList.Add(getListValue(item, tbref.Columns[0].CsName).ToString(), Tuple.Create(item, new List<TNavigate>()));
 | 
				
			||||||
 | 
													} else {
 | 
				
			||||||
 | 
														var sb = new StringBuilder();
 | 
				
			||||||
 | 
														for (var z = 0; z < tbref.Columns.Count; z++) {
 | 
				
			||||||
 | 
															if (z > 0) sb.Append("*$*");
 | 
				
			||||||
 | 
															sb.Append(getListValue(item, tbref.Columns[z].CsName));
 | 
				
			||||||
 | 
														}
 | 
				
			||||||
 | 
														dicList.Add(sb.Remove(0, 3).ToString(), Tuple.Create(item, new List<TNavigate>()));
 | 
				
			||||||
 | 
														sb.Clear();
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												for (var a = 0; a < subList.Count; a++) {
 | 
				
			||||||
 | 
													string key = null;
 | 
				
			||||||
 | 
													if (tbref.Columns.Count == 1) {
 | 
				
			||||||
 | 
														key = _orm.GetEntityValueWithPropertyName(tbref.RefMiddleEntityType, midList[a], tbref.MiddleColumns[0].CsName).ToString();
 | 
				
			||||||
 | 
													} else {
 | 
				
			||||||
 | 
														var sb = new StringBuilder();
 | 
				
			||||||
 | 
														for (var z = 0; z < tbref.Columns.Count; z++) {
 | 
				
			||||||
 | 
															if (z > 0) sb.Append("*$*");
 | 
				
			||||||
 | 
															sb.Append(_orm.GetEntityValueWithPropertyName(tbref.RefMiddleEntityType, midList[a], tbref.MiddleColumns[z].CsName));
 | 
				
			||||||
 | 
														}
 | 
				
			||||||
 | 
														key = sb.ToString();
 | 
				
			||||||
 | 
														sb.Clear();
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
													if (dicList.TryGetValue(key, out var t1item) == false) return;
 | 
				
			||||||
 | 
													t1item.Item2.Add(subList[a]);
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												foreach (var t1item in dicList.Values)
 | 
				
			||||||
 | 
													setListValue(t1item.Item1, t1item.Item2);
 | 
				
			||||||
 | 
												dicList.Clear();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
								return this;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user