Include 贪婪加载第一版,已通过集合的导航数据加载,包括 OneToMany/ManyToMany

This commit is contained in:
28810 2019-05-11 06:17:09 +08:00
parent 04547c06f8
commit 4481064f4e
9 changed files with 425 additions and 29 deletions

View File

@ -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" />

View File

@ -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();
}
} }
} }

View File

@ -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();

View File

@ -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();
}); });

View File

@ -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")

View File

@ -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;
} }
} }

View File

@ -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) {

View File

@ -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()
}; };
}); });

View File

@ -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;
}
} }
} }