Skip to content

Commit defaa22

Browse files
2881028810
authored andcommitted
- 增加 变异的 IncludeMany,即使不是导航属性,也可以贪婪加载;
1 parent 7238f67 commit defaa22

File tree

6 files changed

+96
-11
lines changed

6 files changed

+96
-11
lines changed

FreeSql.Tests/FreeSql.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="FreeSql.DbContext" Version="0.5.12.1" />
10+
<PackageReference Include="FreeSql.DbContext" Version="0.5.17" />
1111
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.8" />
1212
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
1313
<PackageReference Include="xunit" Version="2.4.0" />

FreeSql.Tests/UnitTest1.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ public class Model1 {
9696

9797
public int M2Id { get; set; }
9898

99+
[Column(IsIgnore = true)]
100+
public List<Model1> TestManys { get; set; }
101+
99102
}
100103

101104
public class Model2 {
@@ -133,11 +136,28 @@ public void Test1() {
133136

134137
var includet1 = g.sqlite.Select<Model1>()
135138
.IncludeMany(a => a.Childs, s => s.Where(a => a.id > 0))
139+
.IncludeMany(a => a.TestManys.Where(b => b.id == a.id))
136140
.Where(a => a.id > 10)
137141
.ToList();
138142

139143

140144

145+
146+
147+
148+
149+
150+
151+
152+
153+
154+
155+
156+
157+
158+
159+
160+
141161
var ttt1 = g.sqlite.Select<Model1>().Where(a => a.Childs.AsSelect().Any(b => b.title == "111")).ToList();
142162

143163

FreeSql/FreeSql.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
5-
<Version>0.5.16</Version>
5+
<Version>0.5.17</Version>
66
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
77
<Authors>YeXiangQin</Authors>
88
<Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description>

FreeSql/FreeSql.xml

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

FreeSql/Interface/Curd/ISelect/ISelect1.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,9 @@ public interface ISelect<T1> : ISelect0<ISelect<T1>, T1>, ILinqToSql<T1> where T
305305
/// 贪婪加载集合的导航属性,其实是分两次查询,ToList 后进行了数据重装
306306
/// </summary>
307307
/// <typeparam name="TNavigate"></typeparam>
308-
/// <param name="navigateSelector">选择一个集合的导航属性</param>
308+
/// <param name="navigateSelector">选择一个集合的导航属性,也可通过 .Where 设置临时的关系映射</param>
309309
/// <param name="then">即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?)</param>
310310
/// <returns></returns>
311-
ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, ICollection<TNavigate>>> navigateSelector, Action<ISelect<TNavigate>> then = null) where TNavigate : class;
311+
ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, IEnumerable<TNavigate>>> navigateSelector, Action<ISelect<TNavigate>> then = null) where TNavigate : class;
312312
}
313313
}

FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,20 @@ public ISelect<T1> Include<TNavigate>(Expression<Func<T1, TNavigate>> navigateSe
316316

317317
static MethodInfo GetEntityValueWithPropertyNameMethod = typeof(EntityUtilExtensions).GetMethod("GetEntityValueWithPropertyName");
318318
static ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>> _dicTypeMethod = new ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>>();
319-
public ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, ICollection<TNavigate>>> navigateSelector, Action<ISelect<TNavigate>> then = null) where TNavigate : class {
319+
public ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, IEnumerable<TNavigate>>> navigateSelector, Action<ISelect<TNavigate>> then = null) where TNavigate : class {
320+
var throwNavigateSelector = new Exception("IncludeMany 参数1 类型错误,表达式类型应该为 MemberAccess");
321+
320322
var expBody = navigateSelector?.Body;
321323
if (expBody == null) return this;
322-
if (expBody.NodeType != ExpressionType.MemberAccess) throw new Exception("IncludeMany 参数1 类型错误,表达式类型应该为 MemberAccess");
324+
MethodCallExpression whereExp = null;
325+
if (expBody.NodeType == ExpressionType.Call) {
326+
throwNavigateSelector = new Exception($"IncludeMany {nameof(navigateSelector)} 参数类型错误,表达式格式应该是 a.collection.Where(c => c.aid == a.id)");
327+
whereExp = (expBody as MethodCallExpression);
328+
if (whereExp.Method.Name != "Where") throw throwNavigateSelector;
329+
expBody = whereExp.Object ?? whereExp.Arguments.FirstOrDefault();
330+
}
331+
332+
if (expBody.NodeType != ExpressionType.MemberAccess) throw throwNavigateSelector;
323333
var collMem = expBody as MemberExpression;
324334
Expression tmpExp = collMem.Expression;
325335
var members = new Stack<MemberInfo>();
@@ -335,11 +345,67 @@ public ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, ICollection<TNavig
335345
isbreak = true;
336346
break;
337347
default:
338-
throw new Exception("IncludeMany 参数1 类型错误");
348+
throw throwNavigateSelector;
339349
}
340350
}
341351
var tb = _commonUtils.GetTableByEntity(collMem.Expression.Type);
342-
if (tb == null) throw new Exception("IncludeMany 参数1 类型错误");
352+
if (tb == null) throw throwNavigateSelector;
353+
var tbNav = _commonUtils.GetTableByEntity(typeof(TNavigate));
354+
if (tbNav == null) throw new Exception($"类型 {typeof(TNavigate).FullName} 错误,不能使用 IncludeMany");
355+
TableRef tbref = null;
356+
357+
if (whereExp == null) {
358+
359+
tbref = tb.GetTableRef(collMem.Member.Name, true);
360+
361+
} else {
362+
//处理临时关系映射
363+
tbref = new TableRef {
364+
RefType = TableRefType.OneToMany,
365+
Property = tb.Properties[collMem.Member.Name],
366+
RefEntityType = tbNav.Type
367+
};
368+
foreach (var whereExpArg in whereExp.Arguments) {
369+
if (whereExpArg.NodeType != ExpressionType.Lambda) continue;
370+
var whereExpArgLamb = whereExpArg as LambdaExpression;
371+
372+
Action<Expression> actWeiParse = null;
373+
actWeiParse = expOrg => {
374+
var binaryExp = expOrg as BinaryExpression;
375+
if (binaryExp == null) throw throwNavigateSelector;
376+
377+
switch (binaryExp.NodeType) {
378+
case ExpressionType.AndAlso:
379+
actWeiParse(binaryExp.Left);
380+
actWeiParse(binaryExp.Right);
381+
break;
382+
case ExpressionType.Equal:
383+
var leftP1MemberExp = binaryExp.Left as MemberExpression;
384+
var rightP1MemberExp = binaryExp.Right as MemberExpression;
385+
if (leftP1MemberExp == null || rightP1MemberExp == null) throw throwNavigateSelector;
386+
if (leftP1MemberExp.Expression != tmpExp && leftP1MemberExp.Expression != whereExpArgLamb.Parameters[0] ||
387+
rightP1MemberExp.Expression != tmpExp && rightP1MemberExp.Expression != whereExpArgLamb.Parameters[0]) throw throwNavigateSelector;
388+
389+
if (leftP1MemberExp.Expression == tmpExp && rightP1MemberExp.Expression == whereExpArgLamb.Parameters[0]) {
390+
tbref.Columns.Add(tb.ColumnsByCs[leftP1MemberExp.Member.Name]);
391+
tbref.RefColumns.Add(tbNav.ColumnsByCs[rightP1MemberExp.Member.Name]);
392+
return;
393+
}
394+
if (rightP1MemberExp.Expression == tmpExp && leftP1MemberExp.Expression == whereExpArgLamb.Parameters[0]) {
395+
tbref.Columns.Add(tb.ColumnsByCs[rightP1MemberExp.Member.Name]);
396+
tbref.RefColumns.Add(tbNav.ColumnsByCs[leftP1MemberExp.Member.Name]);
397+
return;
398+
}
399+
400+
throw throwNavigateSelector;
401+
default: throw throwNavigateSelector;
402+
}
403+
};
404+
actWeiParse(whereExpArgLamb.Body);
405+
break;
406+
}
407+
if (tbref.Columns.Any() == false) throw throwNavigateSelector;
408+
}
343409

344410
if (collMem.Expression.NodeType != ExpressionType.Parameter)
345411
_commonExpression.ExpressionWhereLambda(_tables, Expression.MakeMemberAccess(collMem.Expression, tb.Properties[tb.ColumnsByCs.First().Value.CsName]), null);
@@ -349,7 +415,6 @@ public ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, ICollection<TNavig
349415
if (list == null) return;
350416
if (list.Any() == false) return;
351417

352-
var tbref = tb.GetTableRef(collMem.Member.Name, true);
353418
if (tbref.Columns.Any() == false) return;
354419

355420
var t1parm = Expression.Parameter(typeof(T1));

0 commit comments

Comments
 (0)