mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 10:42:52 +08:00
- 增加 变异的 IncludeMany,即使不是导航属性,也可以贪婪加载;
This commit is contained in:
parent
7238f6797b
commit
defaa224fb
@ -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));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user