mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	- 增加 变异的 IncludeMany,即使不是导航属性,也可以贪婪加载;
This commit is contained in:
		@@ -7,7 +7,7 @@
 | 
				
			|||||||
	</PropertyGroup>
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
		<PackageReference Include="FreeSql.DbContext" Version="0.5.12.1" />
 | 
							<PackageReference Include="FreeSql.DbContext" Version="0.5.17" />
 | 
				
			||||||
		<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" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -96,6 +96,9 @@ namespace FreeSql.Tests {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			public int M2Id { get; set; }
 | 
								public int M2Id { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								[Column(IsIgnore = true)]
 | 
				
			||||||
 | 
								public List<Model1> TestManys { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public class Model2 {
 | 
							public class Model2 {
 | 
				
			||||||
@@ -133,11 +136,28 @@ namespace FreeSql.Tests {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			var includet1 = g.sqlite.Select<Model1>()
 | 
								var includet1 = g.sqlite.Select<Model1>()
 | 
				
			||||||
				.IncludeMany(a => a.Childs, s => s.Where(a => a.id > 0))
 | 
									.IncludeMany(a => a.Childs, s => s.Where(a => a.id > 0))
 | 
				
			||||||
 | 
									.IncludeMany(a => a.TestManys.Where(b => b.id == a.id))
 | 
				
			||||||
				.Where(a => a.id > 10)
 | 
									.Where(a => a.id > 10)
 | 
				
			||||||
				.ToList();
 | 
									.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();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<TargetFramework>netstandard2.0</TargetFramework>
 | 
							<TargetFramework>netstandard2.0</TargetFramework>
 | 
				
			||||||
		<Version>0.5.16</Version>
 | 
							<Version>0.5.17</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>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1271,12 +1271,12 @@
 | 
				
			|||||||
            <param name="navigateSelector">选择一个导航属性</param>
 | 
					            <param name="navigateSelector">选择一个导航属性</param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </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}})">
 | 
					        <member name="M:FreeSql.ISelect`1.IncludeMany``1(System.Linq.Expressions.Expression{System.Func{`0,System.Collections.Generic.IEnumerable{``0}}},System.Action{FreeSql.ISelect{``0}})">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            贪婪加载集合的导航属性,其实是分两次查询,ToList 后进行了数据重装
 | 
					            贪婪加载集合的导航属性,其实是分两次查询,ToList 后进行了数据重装
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <typeparam name="TNavigate"></typeparam>
 | 
					            <typeparam name="TNavigate"></typeparam>
 | 
				
			||||||
            <param name="navigateSelector">选择一个集合的导航属性</param>
 | 
					            <param name="navigateSelector">选择一个集合的导航属性,也可通过 .Where 设置临时的关系映射</param>
 | 
				
			||||||
            <param name="then">即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?)</param>
 | 
					            <param name="then">即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?)</param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -305,9 +305,9 @@ namespace FreeSql {
 | 
				
			|||||||
		/// 贪婪加载集合的导航属性,其实是分两次查询,ToList 后进行了数据重装
 | 
							/// 贪婪加载集合的导航属性,其实是分两次查询,ToList 后进行了数据重装
 | 
				
			||||||
		/// </summary>
 | 
							/// </summary>
 | 
				
			||||||
		/// <typeparam name="TNavigate"></typeparam>
 | 
							/// <typeparam name="TNavigate"></typeparam>
 | 
				
			||||||
		/// <param name="navigateSelector">选择一个集合的导航属性</param>
 | 
							/// <param name="navigateSelector">选择一个集合的导航属性,也可通过 .Where 设置临时的关系映射</param>
 | 
				
			||||||
		/// <param name="then">即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?)</param>
 | 
							/// <param name="then">即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?)</param>
 | 
				
			||||||
		/// <returns></returns>
 | 
							/// <returns></returns>
 | 
				
			||||||
		ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, ICollection<TNavigate>>> navigateSelector, Action<ISelect<TNavigate>> then = null) where TNavigate : class;
 | 
							ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, IEnumerable<TNavigate>>> navigateSelector, Action<ISelect<TNavigate>> then = null) where TNavigate : class;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -316,10 +316,20 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		static MethodInfo GetEntityValueWithPropertyNameMethod = typeof(EntityUtilExtensions).GetMethod("GetEntityValueWithPropertyName");
 | 
							static MethodInfo GetEntityValueWithPropertyNameMethod = typeof(EntityUtilExtensions).GetMethod("GetEntityValueWithPropertyName");
 | 
				
			||||||
		static ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>> _dicTypeMethod = new ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>>();
 | 
							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 {
 | 
							public ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, IEnumerable<TNavigate>>> navigateSelector, Action<ISelect<TNavigate>> then = null) where TNavigate : class {
 | 
				
			||||||
 | 
								var throwNavigateSelector = new Exception("IncludeMany 参数1 类型错误,表达式类型应该为 MemberAccess");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var expBody = navigateSelector?.Body;
 | 
								var expBody = navigateSelector?.Body;
 | 
				
			||||||
			if (expBody == null) return this;
 | 
								if (expBody == null) return this;
 | 
				
			||||||
			if (expBody.NodeType != ExpressionType.MemberAccess) throw new Exception("IncludeMany 参数1 类型错误,表达式类型应该为 MemberAccess");
 | 
								MethodCallExpression whereExp = null;
 | 
				
			||||||
 | 
								if (expBody.NodeType == ExpressionType.Call) {
 | 
				
			||||||
 | 
									throwNavigateSelector = new Exception($"IncludeMany {nameof(navigateSelector)} 参数类型错误,表达式格式应该是 a.collection.Where(c => c.aid == a.id)");
 | 
				
			||||||
 | 
									whereExp = (expBody as MethodCallExpression);
 | 
				
			||||||
 | 
									if (whereExp.Method.Name != "Where") throw throwNavigateSelector;
 | 
				
			||||||
 | 
									expBody = whereExp.Object ?? whereExp.Arguments.FirstOrDefault();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (expBody.NodeType != ExpressionType.MemberAccess) throw throwNavigateSelector;
 | 
				
			||||||
			var collMem = expBody as MemberExpression;
 | 
								var collMem = expBody as MemberExpression;
 | 
				
			||||||
			Expression tmpExp = collMem.Expression;
 | 
								Expression tmpExp = collMem.Expression;
 | 
				
			||||||
			var members = new Stack<MemberInfo>();
 | 
								var members = new Stack<MemberInfo>();
 | 
				
			||||||
@@ -335,11 +345,67 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
						isbreak = true;
 | 
											isbreak = true;
 | 
				
			||||||
						break;
 | 
											break;
 | 
				
			||||||
					default:
 | 
										default:
 | 
				
			||||||
						throw new Exception("IncludeMany 参数1 类型错误");
 | 
											throw throwNavigateSelector;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			var tb = _commonUtils.GetTableByEntity(collMem.Expression.Type);
 | 
								var tb = _commonUtils.GetTableByEntity(collMem.Expression.Type);
 | 
				
			||||||
			if (tb == null) throw new Exception("IncludeMany 参数1 类型错误");
 | 
								if (tb == null) throw throwNavigateSelector;
 | 
				
			||||||
 | 
								var tbNav = _commonUtils.GetTableByEntity(typeof(TNavigate));
 | 
				
			||||||
 | 
								if (tbNav == null) throw new Exception($"类型 {typeof(TNavigate).FullName} 错误,不能使用 IncludeMany");
 | 
				
			||||||
 | 
								TableRef tbref = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (whereExp == null) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									tbref = tb.GetTableRef(collMem.Member.Name, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									//处理临时关系映射
 | 
				
			||||||
 | 
									tbref = new TableRef {
 | 
				
			||||||
 | 
										RefType = TableRefType.OneToMany,
 | 
				
			||||||
 | 
										Property = tb.Properties[collMem.Member.Name],
 | 
				
			||||||
 | 
										RefEntityType = tbNav.Type
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
									foreach (var whereExpArg in whereExp.Arguments) {
 | 
				
			||||||
 | 
										if (whereExpArg.NodeType != ExpressionType.Lambda) continue;
 | 
				
			||||||
 | 
										var whereExpArgLamb = whereExpArg as LambdaExpression;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Action<Expression> actWeiParse = null;
 | 
				
			||||||
 | 
										actWeiParse = expOrg => {
 | 
				
			||||||
 | 
											var binaryExp = expOrg as BinaryExpression;
 | 
				
			||||||
 | 
											if (binaryExp == null) throw throwNavigateSelector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											switch (binaryExp.NodeType) {
 | 
				
			||||||
 | 
												case ExpressionType.AndAlso:
 | 
				
			||||||
 | 
													actWeiParse(binaryExp.Left);
 | 
				
			||||||
 | 
													actWeiParse(binaryExp.Right);
 | 
				
			||||||
 | 
													break;
 | 
				
			||||||
 | 
												case ExpressionType.Equal:
 | 
				
			||||||
 | 
													var leftP1MemberExp = binaryExp.Left as MemberExpression;
 | 
				
			||||||
 | 
													var rightP1MemberExp = binaryExp.Right as MemberExpression;
 | 
				
			||||||
 | 
													if (leftP1MemberExp == null || rightP1MemberExp == null) throw throwNavigateSelector;
 | 
				
			||||||
 | 
													if (leftP1MemberExp.Expression != tmpExp && leftP1MemberExp.Expression != whereExpArgLamb.Parameters[0] ||
 | 
				
			||||||
 | 
														rightP1MemberExp.Expression != tmpExp && rightP1MemberExp.Expression != whereExpArgLamb.Parameters[0]) throw throwNavigateSelector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
													if (leftP1MemberExp.Expression == tmpExp && rightP1MemberExp.Expression == whereExpArgLamb.Parameters[0]) {
 | 
				
			||||||
 | 
														tbref.Columns.Add(tb.ColumnsByCs[leftP1MemberExp.Member.Name]);
 | 
				
			||||||
 | 
														tbref.RefColumns.Add(tbNav.ColumnsByCs[rightP1MemberExp.Member.Name]);
 | 
				
			||||||
 | 
														return;
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
													if (rightP1MemberExp.Expression == tmpExp && leftP1MemberExp.Expression == whereExpArgLamb.Parameters[0]) {
 | 
				
			||||||
 | 
														tbref.Columns.Add(tb.ColumnsByCs[rightP1MemberExp.Member.Name]);
 | 
				
			||||||
 | 
														tbref.RefColumns.Add(tbNav.ColumnsByCs[leftP1MemberExp.Member.Name]);
 | 
				
			||||||
 | 
														return;
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
													throw throwNavigateSelector;
 | 
				
			||||||
 | 
												default: throw throwNavigateSelector;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
										actWeiParse(whereExpArgLamb.Body);
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (tbref.Columns.Any() == false) throw throwNavigateSelector;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			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);
 | 
				
			||||||
@@ -349,7 +415,6 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
				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;
 | 
									if (tbref.Columns.Any() == false) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				var t1parm = Expression.Parameter(typeof(T1));
 | 
									var t1parm = Expression.Parameter(typeof(T1));
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user