Skip to content

Commit 58e8771

Browse files
2881028810
authored andcommitted
Merge branch 'IncludeWithJoin'
2 parents 1da596d + fd04042 commit 58e8771

File tree

5 files changed

+178
-15
lines changed

5 files changed

+178
-15
lines changed

FreeSql.Tests/FreeSql.Tests.csproj

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

99
<ItemGroup>
10-
<PackageReference Include="FreeSql.Repository" Version="0.4.11" />
1110
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
1211
<PackageReference Include="xunit" Version="2.4.0" />
1312
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
1413
</ItemGroup>
1514

1615
<ItemGroup>
16+
<ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext\FreeSql.DbContext.csproj" />
1717
<ProjectReference Include="..\FreeSql\FreeSql.csproj" />
1818
</ItemGroup>
1919

FreeSql.Tests/Sqlite/SqliteCodeFirstTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@ namespace FreeSql.Tests.Sqlite {
1010
public class SqliteCodeFirstTest {
1111

1212

13-
class Topic {
13+
public class Topic {
1414
public Guid Id { get; set; }
1515
public string Title { get; set; }
1616
public string Content { get; set; }
1717
public DateTime CreateTime { get; set; }
1818
}
1919
[Table(Name = "xxxtb.Comment")]
20-
class Comment {
20+
public class Comment {
2121
public Guid Id { get; set; }
2222
public Guid TopicId { get; set; }
23-
public Topic Topic { get; set; }
23+
public virtual Topic Topic { get; set; }
2424
public string Nickname { get; set; }
2525
public string Content { get; set; }
2626
public DateTime CreateTime { get; set; }

FreeSql.Tests/UnitTest1.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,30 @@ class ServiceRequestNew {
5454
[Fact]
5555
public void Test1() {
5656

57+
var sqlrepos = g.sqlite.GetRepository<TestTypeParentInfo, int>();
58+
sqlrepos.Insert(new TestTypeParentInfo {
59+
Name = "testroot",
60+
Childs = new[] {
61+
new TestTypeParentInfo {
62+
Name = "testpath2",
63+
Childs = new[] {
64+
new TestTypeParentInfo {
65+
Name = "testpath3",
66+
Childs = new[] {
67+
new TestTypeParentInfo {
68+
Name = "11"
69+
}
70+
}
71+
}
72+
}
73+
}
74+
}
75+
});
76+
77+
var sql = g.sqlite.Select<TestTypeParentInfo>().Where(a => a.Parent.Parent.Parent.Name == "testroot").ToSql();
78+
var sql222 = g.sqlite.Select<TestTypeParentInfo>().Where(a => a.Parent.Parent.Parent.Name == "testroot").ToList();
79+
80+
5781
Expression<Func<TestInfo, object>> orderBy = null;
5882
orderBy = a => a.CreateTime;
5983
var testsql1 = select.OrderBy(orderBy).ToSql();
@@ -332,11 +356,13 @@ class TestTypeInfo {
332356
}
333357

334358
class TestTypeParentInfo {
359+
[Column(IsIdentity = true)]
335360
public int Id { get; set; }
336361
public string Name { get; set; }
337362

338363
public int ParentId { get; set; }
339364
public TestTypeParentInfo Parent { get; set; }
365+
public ICollection<TestTypeParentInfo> Childs { get; set; }
340366

341367
public List<TestTypeInfo> Types { get; set; }
342368
}

FreeSql.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "efcore_to_freesql", "Exampl
2424
EndProject
2525
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "orm_vs", "Examples\orm_vs\orm_vs.csproj", "{1A5EC2EB-8C2B-4547-8AC6-EB5C0DE0CA81}"
2626
EndProject
27+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.DbContext", "..\FreeSql.DbContext\FreeSql.DbContext\FreeSql.DbContext.csproj", "{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}"
28+
EndProject
2729
Global
2830
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2931
Debug|Any CPU = Debug|Any CPU
@@ -118,6 +120,18 @@ Global
118120
{1A5EC2EB-8C2B-4547-8AC6-EB5C0DE0CA81}.Release|x64.Build.0 = Release|Any CPU
119121
{1A5EC2EB-8C2B-4547-8AC6-EB5C0DE0CA81}.Release|x86.ActiveCfg = Release|Any CPU
120122
{1A5EC2EB-8C2B-4547-8AC6-EB5C0DE0CA81}.Release|x86.Build.0 = Release|Any CPU
123+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
124+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
125+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Debug|x64.ActiveCfg = Debug|Any CPU
126+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Debug|x64.Build.0 = Debug|Any CPU
127+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Debug|x86.ActiveCfg = Debug|Any CPU
128+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Debug|x86.Build.0 = Debug|Any CPU
129+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
130+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Release|Any CPU.Build.0 = Release|Any CPU
131+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Release|x64.ActiveCfg = Release|Any CPU
132+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Release|x64.Build.0 = Release|Any CPU
133+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Release|x86.ActiveCfg = Release|Any CPU
134+
{56488C60-FF2C-47ED-B6DD-A38D3CFB84FB}.Release|x86.Build.0 = Release|Any CPU
121135
EndGlobalSection
122136
GlobalSection(SolutionProperties) = preSolution
123137
HideSolutionNode = FALSE

FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs

Lines changed: 134 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ internal static void CopyData(Select0Provider<TSelect, T1> from, object to, Read
4646
//toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<SelectTableInfo>(from._tables.ToArray()));
4747
var _multiTables = toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(to) as List<SelectTableInfo>;
4848
_multiTables[0] = from._tables[0];
49-
for (var a = 1;a < lambParms.Count; a++) {
49+
for (var a = 1; a < lambParms.Count; a++) {
5050
var tb = from._tables.Where(b => b.Alias == lambParms[a].Name && b.Table.Type == lambParms[a].Type).FirstOrDefault();
5151
if (tb != null) _multiTables[a] = tb;
5252
else {
@@ -108,7 +108,7 @@ public TSelect Caching(int seconds, string key = null) {
108108
}
109109
public long Count() => this.ToList<int>("count(1)").FirstOrDefault();
110110
async public Task<long> CountAsync() => (await this.ToListAsync<int>("count(1)")).FirstOrDefault();
111-
111+
112112
public TSelect Count(out long count) {
113113
count = this.Count();
114114
return this as TSelect;
@@ -235,7 +235,7 @@ public List<TTuple> ToList<TTuple>(string field) {
235235
Type type = typeof(TTuple);
236236
_orm.Ado.ExecuteReader(_connection, _transaction, dr => {
237237
var read = Utils.ExecuteArrayRowReadClassOrTuple(type, null, dr, 0, _commonUtils);
238-
ret.Add((TTuple)read.Value);
238+
ret.Add((TTuple) read.Value);
239239
}, CommandType.Text, sql, _params.ToArray());
240240
_orm.Aop.ToList?.Invoke(this, new AopToListEventArgs(ret));
241241
_trackToList?.Invoke(ret);
@@ -251,7 +251,7 @@ public Task<List<TTuple>> ToListAsync<TTuple>(string field) {
251251
Type type = typeof(TTuple);
252252
await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, dr => {
253253
var read = Utils.ExecuteArrayRowReadClassOrTuple(type, null, dr, 0, _commonUtils);
254-
ret.Add((TTuple)read.Value);
254+
ret.Add((TTuple) read.Value);
255255
return Task.CompletedTask;
256256
}, CommandType.Text, sql, _params.ToArray());
257257
_orm.Aop.ToList?.Invoke(this, new AopToListEventArgs(ret));
@@ -311,7 +311,7 @@ protected List<TReturn> ToListMapReader<TReturn>((ReadAnonymousTypeInfo map, str
311311
Type type = typeof(TReturn);
312312
_orm.Ado.ExecuteReader(_connection, _transaction, dr => {
313313
var index = -1;
314-
ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index, false));
314+
ret.Add((TReturn) _commonExpression.ReadAnonymous(af.map, dr, ref index, false));
315315
}, CommandType.Text, sql, _params.ToArray());
316316
_orm.Aop.ToList?.Invoke(this, new AopToListEventArgs(ret));
317317
_trackToList?.Invoke(ret);
@@ -327,7 +327,7 @@ async protected Task<List<TReturn>> ToListMapReaderAsync<TReturn>((ReadAnonymous
327327
Type type = typeof(TReturn);
328328
await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, dr => {
329329
var index = -1;
330-
ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index, false));
330+
ret.Add((TReturn) _commonExpression.ReadAnonymous(af.map, dr, ref index, false));
331331
return Task.CompletedTask;
332332
}, CommandType.Text, sql, _params.ToArray());
333333
_orm.Aop.ToList?.Invoke(this, new AopToListEventArgs(ret));
@@ -350,6 +350,126 @@ public class GetAllFieldExpressionTreeInfo {
350350
public Func<IFreeSql, DbDataReader, T1> Read { get; set; }
351351
}
352352
protected GetAllFieldExpressionTreeInfo GetAllFieldExpressionTree() {
353+
return _dicGetAllFieldExpressionTree.GetOrAdd(string.Join("+", _tables.Select(a => $"{_orm.Ado.DataType}-{a.Table.DbName}-{a.Alias}-{a.Type}")), s => {
354+
var type = _tables.First().Table.TypeLazy ?? _tables.First().Table.Type;
355+
var ormExp = Expression.Parameter(typeof(IFreeSql), "orm");
356+
var rowExp = Expression.Parameter(typeof(DbDataReader), "row");
357+
var returnTarget = Expression.Label(type);
358+
var retExp = Expression.Variable(type, "ret");
359+
var dataIndexExp = Expression.Variable(typeof(int), "dataIndex");
360+
var readExp = Expression.Variable(typeof(Utils.RowInfo), "read");
361+
var readExpValue = Expression.MakeMemberAccess(readExp, Utils.RowInfo.PropertyValue);
362+
var readExpDataIndex = Expression.MakeMemberAccess(readExp, Utils.RowInfo.PropertyDataIndex);
363+
var blockExp = new List<Expression>();
364+
var ctor = type.GetConstructor(new Type[0]) ?? type.GetConstructors().First();
365+
blockExp.AddRange(new Expression[] {
366+
Expression.Assign(retExp, Expression.New(ctor, ctor.GetParameters().Select(a => Expression.Default(a.ParameterType)))),
367+
Expression.Assign(dataIndexExp, Expression.Constant(0))
368+
});
369+
//typeof(Topic).GetMethod("get_Type").IsVirtual
370+
371+
var field = new StringBuilder();
372+
var dicfield = new Dictionary<string, bool>();
373+
var tb = _tables.First();
374+
var index = 0;
375+
376+
var tbiindex = 0;
377+
foreach (var tbi in _tables.ToArray().OrderBy(a => a.Alias)) {
378+
if (tbiindex > 0 && tbi.Type == SelectTableInfoType.From) continue;
379+
if (tbiindex > 0 && tbi.Alias.StartsWith($"{tb.Alias}__") == false) continue;
380+
381+
var typei = tbi.Table.TypeLazy ?? tbi.Table.Type;
382+
if (tbiindex == 0)
383+
blockExp.AddRange(new Expression[] {
384+
Expression.Assign(readExp, Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(typei), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp, Expression.Constant(_commonUtils) })),
385+
Expression.IfThen(
386+
Expression.GreaterThan(readExpDataIndex, dataIndexExp),
387+
Expression.Assign(dataIndexExp, readExpDataIndex)
388+
),
389+
Expression.IfThen(
390+
Expression.NotEqual(readExpValue, Expression.Constant(null)),
391+
Expression.Assign(retExp, Expression.Convert(readExpValue, typei))
392+
)
393+
});
394+
else {
395+
Expression curExpIfNotNull = Expression.IsTrue(Expression.Constant(true));
396+
Expression curExp = retExp;
397+
var curTb = tb;
398+
var parentNameSplits = tbi.Alias.Split(new[] { "__" }, StringSplitOptions.None);
399+
var iscontinue = false;
400+
for (var k = 1; k < parentNameSplits.Length; k++) {
401+
var curPropName = parentNameSplits[k];
402+
if (curTb.Table.Properties.TryGetValue(parentNameSplits[k], out var tryprop) == false) {
403+
k++;
404+
curPropName = $"{curPropName}__{parentNameSplits[k]}";
405+
if (curTb.Table.Properties.TryGetValue(parentNameSplits[k], out tryprop) == false) {
406+
iscontinue = true;
407+
break;
408+
}
409+
}
410+
curExp = Expression.MakeMemberAccess(curExp, tryprop);
411+
if (k + 1 < parentNameSplits.Length)
412+
curExpIfNotNull = Expression.AndAlso(curExpIfNotNull, Expression.NotEqual(curExp, Expression.Default(tryprop.PropertyType)));
413+
curTb = _tables.Where(a => a.Alias == $"{curTb.Alias}__{curPropName}" && a.Table.Type == tryprop.PropertyType).FirstOrDefault();
414+
if (curTb == null) {
415+
iscontinue = true;
416+
break;
417+
}
418+
}
419+
if (iscontinue) continue;
420+
421+
blockExp.Add(
422+
Expression.IfThen(
423+
curExpIfNotNull,
424+
Expression.Block(new Expression[] {
425+
Expression.Assign(readExp, Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(typei), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp, Expression.Constant(_commonUtils) })),
426+
Expression.IfThen(
427+
Expression.GreaterThan(readExpDataIndex, dataIndexExp),
428+
Expression.Assign(dataIndexExp, readExpDataIndex)
429+
),
430+
Expression.IfThen(
431+
Expression.NotEqual(readExpValue, Expression.Constant(null)),
432+
Expression.Assign(curExp, Expression.Convert(readExpValue, typei))
433+
)
434+
})
435+
)
436+
);
437+
}
438+
if (tbi.Table.TypeLazy != null)
439+
blockExp.Add(
440+
Expression.IfThen(
441+
Expression.NotEqual(readExpValue, Expression.Constant(null)),
442+
Expression.Call(retExp, tbi.Table.TypeLazySetOrm, ormExp)
443+
)
444+
); //将 orm 传递给 lazy
445+
446+
var colidx = 0;
447+
foreach (var col in tbi.Table.Columns.Values) {
448+
if (index > 0) {
449+
field.Append(", ");
450+
if (tbiindex > 0 && colidx == 0) field.Append("\r\n");
451+
}
452+
var quoteName = _commonUtils.QuoteSqlName(col.Attribute.Name);
453+
field.Append(_commonUtils.QuoteReadColumn(col.CsType, $"{tbi.Alias}.{quoteName}"));
454+
++index;
455+
if (dicfield.ContainsKey(quoteName)) field.Append(" as").Append(index);
456+
else dicfield.Add(quoteName, true);
457+
++colidx;
458+
}
459+
tbiindex++;
460+
}
461+
462+
blockExp.AddRange(new Expression[] {
463+
Expression.Return(returnTarget, retExp),
464+
Expression.Label(returnTarget, Expression.Default(type))
465+
});
466+
return new GetAllFieldExpressionTreeInfo {
467+
Field = field.ToString(),
468+
Read = Expression.Lambda<Func<IFreeSql, DbDataReader, T1>>(Expression.Block(new[] { retExp, dataIndexExp, readExp }, blockExp), new[] { ormExp, rowExp }).Compile()
469+
};
470+
});
471+
}
472+
protected GetAllFieldExpressionTreeInfo GetAllFieldExpressionTreeLevel2() {
353473
return _dicGetAllFieldExpressionTree.GetOrAdd(string.Join("+", _tables.Select(a => $"{_orm.Ado.DataType}-{a.Table.DbName}-{a.Alias}-{a.Type}")), s => {
354474
var tb1 = _tables.First().Table;
355475
var type = tb1.TypeLazy ?? tb1.Type;
@@ -387,12 +507,14 @@ protected GetAllFieldExpressionTreeInfo GetAllFieldExpressionTree() {
387507
if (dicfield.ContainsKey(quoteName)) field.Append(" as").Append(index);
388508
else dicfield.Add(quoteName, true);
389509
} else {
390-
var tb2 = _tables.Where((a, b) => b > 0 &&
391-
(a.Type == SelectTableInfoType.InnerJoin || a.Type == SelectTableInfoType.LeftJoin || a.Type == SelectTableInfoType.RightJoin) &&
510+
var tb2 = _tables.Where((a, b) => b > 0 &&
511+
(a.Type == SelectTableInfoType.InnerJoin || a.Type == SelectTableInfoType.LeftJoin || a.Type == SelectTableInfoType.RightJoin) &&
392512
string.IsNullOrEmpty(a.On) == false &&
393-
a.Alias.Contains(prop.Name)).FirstOrDefault(); //判断 b > 0 防止 parent 递归关系
513+
a.Alias.StartsWith($"{tb.Alias}__") && //开头结尾完全匹配
514+
a.Alias.EndsWith($"__{prop.Name}") //不清楚会不会有其他情况 求大佬优化
515+
).FirstOrDefault(); //判断 b > 0 防止 parent 递归关系
394516
if (tb2 == null && props.Where(pw => pw.Value.PropertyType == prop.PropertyType).Count() == 1)
395-
tb2 = _tables.Where((a, b) => b > 0 &&
517+
tb2 = _tables.Where((a, b) => b > 0 &&
396518
(a.Type == SelectTableInfoType.InnerJoin || a.Type == SelectTableInfoType.LeftJoin || a.Type == SelectTableInfoType.RightJoin) &&
397519
string.IsNullOrEmpty(a.On) == false &&
398520
a.Table.Type == prop.PropertyType).FirstOrDefault();
@@ -501,7 +623,8 @@ protected GetAllFieldExpressionTreeInfo GetAllFieldExpressionTree() {
501623
else dicfield.Add(quoteName, true);
502624
child.Childs.Add(new ReadAnonymousTypeInfo {
503625
Property = tb2.Table.Type.GetProperty(col2.CsName, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance),
504-
CsName = col2.CsName });
626+
CsName = col2.CsName
627+
});
505628
}
506629
}
507630
map.Childs.Add(child);

0 commit comments

Comments
 (0)