mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-06-20 04:48:16 +08:00
- 增加 IncludeMany 贪婪加载的时候可指定子表的字段,避免查询子表所有字段;
This commit is contained in:
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
Reference in New Issue
Block a user