- 增加 IncludeMany 贪婪加载的时候可指定子表的字段,避免查询子表所有字段;

This commit is contained in:
28810
2019-11-18 03:22:34 +08:00
parent 769c1f020c
commit 1083f371a9
16 changed files with 1899 additions and 343 deletions

View File

@ -108,31 +108,34 @@ namespace FreeSql.Internal
parent.Consturctor = initExp.NewExpression.Type.GetConstructors()[0];
parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties;
//dto 映射
var dtoProps = initExp.NewExpression.Type.GetPropertiesDictIgnoreCase().Values;
foreach (var dtoProp in dtoProps)
if (initExp.NewExpression.Type != _tables.FirstOrDefault()?.Table.Type)
{
foreach (var dtTb in _tables)
//dto 映射
var dtoProps = initExp.NewExpression.Type.GetPropertiesDictIgnoreCase().Values;
foreach (var dtoProp in dtoProps)
{
if (dtTb.Table.Columns.TryGetValue(dtoProp.Name, out var trydtocol))
foreach (var dtTb in _tables)
{
var child = new ReadAnonymousTypeInfo
if (dtTb.Table.Columns.TryGetValue(dtoProp.Name, out var trydtocol))
{
Property = dtoProp,
CsName = dtoProp.Name,
CsType = dtoProp.PropertyType,
MapType = trydtocol.Attribute.MapType
};
parent.Childs.Add(child);
if (dtTb.Parameter != null)
ReadAnonymousField(_tables, field, child, ref index, Expression.Property(dtTb.Parameter, dtTb.Table.Properties[trydtocol.CsName]), getSelectGroupingMapString, whereCascadeExpression);
else
{
child.DbField = $"{dtTb.Alias}.{_common.QuoteSqlName(trydtocol.Attribute.Name)}";
field.Append(", ").Append(child.DbField);
if (index >= 0) field.Append(" as").Append(++index);
var child = new ReadAnonymousTypeInfo
{
Property = dtoProp,
CsName = dtoProp.Name,
CsType = dtoProp.PropertyType,
MapType = trydtocol.Attribute.MapType
};
parent.Childs.Add(child);
if (dtTb.Parameter != null)
ReadAnonymousField(_tables, field, child, ref index, Expression.Property(dtTb.Parameter, dtTb.Table.Properties[trydtocol.CsName]), getSelectGroupingMapString, whereCascadeExpression);
else
{
child.DbField = $"{dtTb.Alias}.{_common.QuoteSqlName(trydtocol.Attribute.Name)}";
field.Append(", ").Append(child.DbField);
if (index >= 0) field.Append(" as").Append(++index);
}
break;
}
break;
}
}
}

View File

@ -462,9 +462,8 @@ namespace FreeSql.Internal.CommonProvider
public T1 First() => this.ToOne();
protected List<TReturn> ToListMapReader<TReturn>((ReadAnonymousTypeInfo map, string field) af)
internal List<TReturn> ToListMrPrivate<TReturn>(string sql, (ReadAnonymousTypeInfo map, string field) af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
{
var sql = this.ToSql(af.field);
var type = typeof(TReturn);
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
@ -477,6 +476,9 @@ namespace FreeSql.Internal.CommonProvider
{
var index = -1;
ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index, false));
if (otherData != null)
foreach (var other in otherData)
other.retlist.Add(_commonExpression.ReadAnonymous(other.read, dr, ref index, false));
}, CommandType.Text, sql, dbParms);
}
catch (Exception ex)
@ -489,9 +491,27 @@ namespace FreeSql.Internal.CommonProvider
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfter?.Invoke(this, after);
}
if (typeof(TReturn) == typeof(T1))
foreach (var include in _includeToList) include?.Invoke(ret);
_trackToList?.Invoke(ret);
return ret;
}
internal List<TReturn> ToListMapReaderPrivate<TReturn>((ReadAnonymousTypeInfo map, string field) af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
{
string sql = null;
if (otherData?.Length > 0)
{
var sbField = new StringBuilder().Append(af.field);
foreach (var other in otherData)
sbField.Append(other.field);
sql = this.ToSql(sbField.ToString());
}
else
sql = this.ToSql(af.field);
return ToListMrPrivate<TReturn>(sql, af, otherData);
}
protected List<TReturn> ToListMapReader<TReturn>((ReadAnonymousTypeInfo map, string field) af) => ToListMapReaderPrivate<TReturn>(af, null);
protected (ReadAnonymousTypeInfo map, string field) GetExpressionField(Expression newexp)
{
var map = new ReadAnonymousTypeInfo();
@ -1163,9 +1183,8 @@ namespace FreeSql.Internal.CommonProvider
public Task<T1> FirstAsync() => this.ToOneAsync();
async protected Task<List<TReturn>> ToListMapReaderAsync<TReturn>((ReadAnonymousTypeInfo map, string field) af)
async internal Task<List<TReturn>> ToListMrPrivateAsync<TReturn>(string sql, (ReadAnonymousTypeInfo map, string field) af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
{
var sql = this.ToSql(af.field);
var type = typeof(TReturn);
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
@ -1178,6 +1197,9 @@ namespace FreeSql.Internal.CommonProvider
{
var index = -1;
ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index, false));
if (otherData != null)
foreach (var other in otherData)
other.retlist.Add(_commonExpression.ReadAnonymous(other.read, dr, ref index, false));
return Task.FromResult(false);
}, CommandType.Text, sql, dbParms);
}
@ -1191,9 +1213,27 @@ namespace FreeSql.Internal.CommonProvider
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfter?.Invoke(this, after);
}
if (typeof(TReturn) == typeof(T1))
foreach (var include in _includeToList) include?.Invoke(ret);
_trackToList?.Invoke(ret);
return ret;
}
internal Task<List<TReturn>> ToListMapReaderPrivateAsync<TReturn>((ReadAnonymousTypeInfo map, string field) af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
{
string sql = null;
if (otherData?.Length > 0)
{
var sbField = new StringBuilder().Append(af.field);
foreach (var other in otherData)
sbField.Append(other.field);
sql = this.ToSql(sbField.ToString());
}
else
sql = this.ToSql(af.field);
return ToListMrPrivateAsync<TReturn>(sql, af, otherData);
}
protected Task<List<TReturn>> ToListMapReaderAsync<TReturn>((ReadAnonymousTypeInfo map, string field) af) => ToListMapReaderPrivateAsync<TReturn>(af, null);
async protected Task<TMember> InternalAvgAsync<TMember>(Expression exp) => (await this.ToListAsync<TMember>($"avg({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)})")).FirstOrDefault();
async protected Task<TMember> InternalMaxAsync<TMember>(Expression exp) => (await this.ToListAsync<TMember>($"max({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)})")).FirstOrDefault();

View File

@ -386,16 +386,23 @@ namespace FreeSql.Internal.CommonProvider
if (expBody == null) return this;
MethodCallExpression whereExp = null;
int takeNumber = 0;
Expression<Func<TNavigate, TNavigate>> selectExp = null;
while (expBody.NodeType == ExpressionType.Call)
{
throwNavigateSelector = new Exception($"IncludeMany {nameof(navigateSelector)} 参数类型错误,表达式格式应该是 a.collections.Take(1).Where(c => c.aid == a.id)");
throwNavigateSelector = new Exception($"IncludeMany {nameof(navigateSelector)} 参数类型错误,正确格式: a.collections.Take(1).Where(c => c.aid == a.id).Select(a => new TNavigate {{ }})");
var callExp = (expBody as MethodCallExpression);
switch (callExp.Method.Name)
{
case "Where":
whereExp = callExp;
break;
case "Take": takeNumber = int.Parse((callExp.Arguments[1] as ConstantExpression)?.Value?.ToString() ?? "0"); break;
case "Take":
takeNumber = int.Parse(_commonExpression.ExpressionLambdaToSql(callExp.Arguments[1], new CommonExpression.ExpTSC { }));
break;
case "Select":
selectExp = (callExp.Arguments[1] as Expression<Func<TNavigate, TNavigate>>);
if (selectExp?.Parameters.Count != 1) throw new Exception($"IncludeMany {nameof(navigateSelector)} 参数错误Select 只可以使用一个参数的方法,正确格式: .Select(t => new TNavigate {{ }})");
break;
default: throw throwNavigateSelector;
}
expBody = callExp.Object ?? callExp.Arguments.FirstOrDefault();
@ -406,6 +413,9 @@ namespace FreeSql.Internal.CommonProvider
var (membersParam, members) = GetExpressionStack(collMem.Expression);
var tb = _commonUtils.GetTableByEntity(collMem.Expression.Type);
if (tb == null) throw throwNavigateSelector;
var collMemElementType = (collMem.Type.IsGenericType ? collMem.Type.GetGenericArguments().FirstOrDefault() : collMem.Type.GetElementType());
if (typeof(TNavigate) != collMemElementType)
throw new Exception($"IncludeMany {nameof(navigateSelector)} 参数错误Select lambda参数返回值必须和 {collMemElementType} 类型一致");
var tbNav = _commonUtils.GetTableByEntity(typeof(TNavigate));
if (tbNav == null) throw new Exception($"类型 {typeof(TNavigate).FullName} 错误,不能使用 IncludeMany");
@ -588,6 +598,22 @@ namespace FreeSql.Internal.CommonProvider
var oldWhere = subSelect._where.ToString();
if (oldWhere.StartsWith(" AND ")) oldWhere = oldWhere.Remove(0, 5);
if (selectExp != null)
{
var tmpinitExp = selectExp.Body as MemberInitExpression;
var newinitExpBindings = tmpinitExp.Bindings.ToList();
foreach (var tbrefCol in tbref.RefColumns)
{
if (newinitExpBindings.Any(a => a.Member.Name == tbrefCol.CsName)) continue;
var tmpMemberInfo = tbrefCol.Table.Properties[tbrefCol.CsName];
newinitExpBindings.Add(Expression.Bind(tmpMemberInfo, Expression.MakeMemberAccess(selectExp.Parameters[0], tmpMemberInfo)));
}
Expression newinitExp = Expression.MemberInit(tmpinitExp.NewExpression, newinitExpBindings.ToList());
var selectExpParam = subSelect._tables[0].Parameter ?? Expression.Parameter(typeof(TNavigate), subSelectT1Alias);
newinitExp = new NewExpressionVisitor(selectExpParam, selectExp.Parameters[0]).Replace(newinitExp);
selectExp = Expression.Lambda<Func<TNavigate, TNavigate>>(newinitExp, selectExpParam);
}
switch (tbref.RefType)
{
case TableRefType.OneToMany:
@ -616,19 +642,23 @@ namespace FreeSql.Internal.CommonProvider
};
if (takeNumber > 0)
{
var af = subSelect.GetAllFieldExpressionTreeLevelAll();
Select0Provider<ISelect<TNavigate>, TNavigate>.GetAllFieldExpressionTreeInfo af = null;
(ReadAnonymousTypeInfo map, string field) mf = default;
if (selectExp == null) af = subSelect.GetAllFieldExpressionTreeLevelAll();
else mf = subSelect.GetExpressionField(selectExp);
var sbSql = new StringBuilder();
var sbDic = getWhereDic();
foreach (var sbd in sbDic)
{
subSelect._where.Clear();
subSelect.Where(sbd.Key).Where(oldWhere).Limit(takeNumber);
sbSql.Append("\r\nUNION ALL\r\nselect * from (").Append(subSelect.ToSql(af.Field)).Append(") ftb");
sbSql.Append("\r\nUNION ALL\r\nselect * from (").Append(subSelect.ToSql(selectExp == null ? af.Field : mf.field)).Append(") ftb");
}
sbSql.Remove(0, 13);
if (sbDic.Count == 1) sbSql.Remove(0, 15).Remove(sbSql.Length - 5, 5);
sbDic.Clear();
subList = subSelect.ToListAfPrivate(sbSql.ToString(), af, null);
if (selectExp == null) subList = subSelect.ToListAfPrivate(sbSql.ToString(), af, null);
else subList = subSelect.ToListMrPrivate<TNavigate>(sbSql.ToString(), mf, null);
sbSql.Clear();
}
else
@ -658,7 +688,8 @@ namespace FreeSql.Internal.CommonProvider
sbDic.Clear();
}
subSelect.Where(oldWhere);
subList = subSelect.ToList(true);
if (selectExp == null) subList = subSelect.ToList(true);
else subList = subSelect.ToList<TNavigate>(selectExp);
}
if (subList.Any() == false)
@ -760,7 +791,10 @@ namespace FreeSql.Internal.CommonProvider
subSelect.InnerJoin(sbJoin.ToString());
sbJoin.Clear();
var af = subSelect.GetAllFieldExpressionTreeLevelAll();
Select0Provider<ISelect<TNavigate>, TNavigate>.GetAllFieldExpressionTreeInfo af = null;
(ReadAnonymousTypeInfo map, string field) mf = default;
if (selectExp == null) af = subSelect.GetAllFieldExpressionTreeLevelAll();
else mf = subSelect.GetExpressionField(selectExp);
(string field, ReadAnonymousTypeInfo read)? otherData = null;
var sbSql = new StringBuilder();
@ -814,7 +848,7 @@ namespace FreeSql.Internal.CommonProvider
{
subSelect._where.Clear();
subSelect.Where(sbd.Key).Where(oldWhere).Limit(takeNumber);
sbSql.Append("\r\nUNION ALL\r\nselect * from (").Append(subSelect.ToSql($"{af.Field}{otherData?.field}")).Append(") ftb");
sbSql.Append("\r\nUNION ALL\r\nselect * from (").Append(subSelect.ToSql($"{(selectExp == null ? af.Field : mf.field)}{otherData?.field}")).Append(") ftb");
}
sbSql.Remove(0, 13);
if (sbDic.Count == 1) sbSql.Remove(0, 15).Remove(sbSql.Length - 5, 5);
@ -838,10 +872,11 @@ namespace FreeSql.Internal.CommonProvider
sbDic.Clear();
}
subSelect.Where(oldWhere);
sbSql.Append(subSelect.ToSql($"{af.Field}{otherData?.field}"));
sbSql.Append(subSelect.ToSql($"{(selectExp == null ? af.Field : mf.field)}{otherData?.field}"));
}
subList = subSelect.ToListAfPrivate(sbSql.ToString(), af, otherData == null ? null : new[] { (otherData.Value.field, otherData.Value.read, midList) });
if (selectExp == null) subList = subSelect.ToListAfPrivate(sbSql.ToString(), af, otherData == null ? null : new[] { (otherData.Value.field, otherData.Value.read, midList) });
else subList = subSelect.ToListMrPrivate<TNavigate>(sbSql.ToString(), mf, otherData == null ? null : new[] { (otherData.Value.field, otherData.Value.read, midList) });
if (subList.Any() == false)
{
foreach (var item in list)