mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 10:42:52 +08:00
- 优化 Limit + Sum/Avg/Max/Min 为嵌套查询;
This commit is contained in:
parent
3b961681dc
commit
27cb11e4a7
@ -9,7 +9,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>3.2.651</Version>
|
||||
<Version>3.2.660-preview22020525</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1001,10 +1001,15 @@ limit 0,10", t1);
|
||||
var subquery = select.ToSql(a => new
|
||||
{
|
||||
all = a,
|
||||
count = (long)select.As("b").Sum(b => b.Id)
|
||||
count = (long)select.As("b").Sum(b => b.Id),
|
||||
sum2 = (long)select.As("b").Limit(10).Sum(b => b.Id)
|
||||
});
|
||||
Assert.Equal(@"SELECT a.""Id"" as1, a.""Clicks"" as2, a.""TypeGuid"" as3, a.""Title"" as4, a.""CreateTime"" as5, ifnull((SELECT sum(b.""Id"")
|
||||
FROM ""tb_topic22"" b), 0) as6
|
||||
FROM ""tb_topic22"" b), 0) as6, ifnull((SELECT sum(ftba.""Id"") FROM (
|
||||
SELECT b.""Id""
|
||||
FROM ""tb_topic22"" b
|
||||
limit 0,10
|
||||
) ftba), 0) as7
|
||||
FROM ""tb_topic22"" a", subquery);
|
||||
var subqueryList = select.ToList(a => new
|
||||
{
|
||||
|
@ -1362,9 +1362,15 @@ namespace FreeSql.Internal
|
||||
var exp3Args0 = (exp3.Arguments.FirstOrDefault() as UnaryExpression)?.Operand as LambdaExpression;
|
||||
if (exp3Args0.Parameters.Count == 1 && exp3Args0.Parameters[0].Type.FullName.StartsWith("FreeSql.Internal.Model.HzyTuple`"))
|
||||
exp3Args0 = new ReplaceHzyTupleToMultiParam().Modify(exp3Args0, fsqltables);
|
||||
var sqlSum = fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { $"{exp3.Method.Name.ToLower()}({ExpressionLambdaToSql(exp3Args0, tscClone1)})" })?.ToString();
|
||||
var sqlSumField = $"{exp3.Method.Name.ToLower()}({ExpressionLambdaToSql(exp3Args0, tscClone1)})";
|
||||
var sqlSum = tscClone1.subSelect001._limit <= 0 && tscClone1.subSelect001._skip <= 0 ?
|
||||
fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { $"{exp3.Method.Name.ToLower()}({ExpressionLambdaToSql(exp3Args0, tscClone1)})" })?.ToString() :
|
||||
tscClone1.subSelect001.GetNestSelectSql(exp3Args0, sqlSumField, tosqlField =>
|
||||
fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { tosqlField })?.ToString());
|
||||
if (string.IsNullOrEmpty(sqlSum) == false)
|
||||
return _common.IsNull($"({sqlSum.Replace(" \r\n", " \r\n ")})", 0);
|
||||
return tscClone1.subSelect001._limit <= 0 && tscClone1.subSelect001._skip <= 0 ?
|
||||
_common.IsNull($"({sqlSum.Replace(" \r\n", " \r\n ")})", 0) :
|
||||
_common.IsNull($"({sqlSum})", 0);
|
||||
break;
|
||||
case "ToList":
|
||||
case "ToOne":
|
||||
|
@ -243,6 +243,113 @@ namespace FreeSql.Internal.CommonProvider
|
||||
}
|
||||
return newExp;
|
||||
}
|
||||
|
||||
public ReadAnonymousTypeAfInfo GetExpressionField(Expression newexp, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
|
||||
{
|
||||
var map = new ReadAnonymousTypeInfo();
|
||||
var field = new StringBuilder();
|
||||
var index = fieldAlias == FieldAliasOptions.AsProperty ? CommonExpression.ReadAnonymousFieldAsCsName : 0;
|
||||
|
||||
_commonExpression.ReadAnonymousField(_tables, field, map, ref index, newexp, this, null, _whereGlobalFilter, null, null, true);
|
||||
return new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null);
|
||||
}
|
||||
public string GetNestSelectSql(Expression select, string affield, Func<string, string> ToSql)
|
||||
{
|
||||
var allMemExps = new FindAllMemberExpressionVisitor(this);
|
||||
allMemExps.Visit(select);
|
||||
var fieldAlias = new Dictionary<string, bool>();
|
||||
var fieldReplaced = new Dictionary<string, bool>();
|
||||
var field = new StringBuilder();
|
||||
foreach (var memExp in allMemExps.Result)
|
||||
{
|
||||
var gef = GetExpressionField(memExp.Item1, FieldAliasOptions.AsProperty);
|
||||
var geffield = gef.field;
|
||||
if (fieldReplaced.ContainsKey(geffield)) continue;
|
||||
fieldReplaced.Add(geffield, true);
|
||||
|
||||
field.Append(", ").Append(gef.field);
|
||||
if (fieldAlias.ContainsKey(memExp.Item2.Attribute.Name))
|
||||
{
|
||||
field.Append(_commonUtils.FieldAsAlias($"aas{fieldAlias.Count}"));
|
||||
affield = affield.Replace(geffield, $"ftba.aas{fieldAlias.Count}");
|
||||
}
|
||||
else
|
||||
{
|
||||
fieldAlias.Add(memExp.Item2.Attribute.Name, true);
|
||||
affield = affield.Replace(geffield, $"ftba.{string.Join(".", geffield.Split('.').Skip(1))}");
|
||||
}
|
||||
}
|
||||
|
||||
var sql = ToSql(field.Remove(0, 2).ToString());
|
||||
sql = $"{_select} {affield} FROM ( \r\n {sql.Replace("\r\n", "\r\n ")}\r\n) ftba";
|
||||
field.Clear();
|
||||
return sql;
|
||||
}
|
||||
public class FindAllMemberExpressionVisitor : ExpressionVisitor
|
||||
{
|
||||
public List<NativeTuple<MemberExpression, ColumnInfo>> Result { get; set; } = new List<NativeTuple<MemberExpression, ColumnInfo>>();
|
||||
Select0Provider _select;
|
||||
public FindAllMemberExpressionVisitor(Select0Provider select) => _select = select;
|
||||
|
||||
protected override Expression VisitMember(MemberExpression node)
|
||||
{
|
||||
var exps = new Stack<Expression>();
|
||||
Expression exp = node;
|
||||
while (exp != null)
|
||||
{
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.Parameter:
|
||||
exps.Push(exp);
|
||||
exp = null;
|
||||
continue;
|
||||
case ExpressionType.MemberAccess:
|
||||
exps.Push(exp);
|
||||
exp = (exp as MemberExpression)?.Expression;
|
||||
continue;
|
||||
}
|
||||
return base.VisitMember(node);
|
||||
}
|
||||
if (exps.Any() == false) return base.VisitMember(node);
|
||||
var firstExp = exps.Pop() as ParameterExpression;
|
||||
if (firstExp == null) return base.VisitMember(node);
|
||||
var tb = _select._tables.Find(a => a.Parameter == firstExp)?.Table;
|
||||
if (tb == null) return base.VisitMember(node);
|
||||
|
||||
while (exps.Any())
|
||||
{
|
||||
var memExp = exps.Pop() as MemberExpression;
|
||||
if (tb.ColumnsByCs.TryGetValue(memExp.Member.Name, out var trycol) && exps.Any() == false)
|
||||
{
|
||||
Result.Add(NativeTuple.Create(node, trycol));
|
||||
return node;
|
||||
}
|
||||
if (tb.Properties.ContainsKey(memExp.Member.Name))
|
||||
{
|
||||
tb = _select._commonUtils.GetTableByEntity(memExp.Type);
|
||||
if (tb == null) return base.VisitMember(node);
|
||||
}
|
||||
}
|
||||
return base.VisitMember(node);
|
||||
}
|
||||
}
|
||||
public class ReplaceMemberExpressionVisitor : ExpressionVisitor
|
||||
{
|
||||
Expression _findExp;
|
||||
Expression _replaceExp;
|
||||
public Expression Replace(Expression exp, Expression find, Expression replace) // object repval)
|
||||
{
|
||||
_findExp = find;
|
||||
_replaceExp = replace;
|
||||
//_replaceExp = Expression.Constant(repval, find.Type);
|
||||
return this.Visit(exp);
|
||||
}
|
||||
protected override Expression VisitMember(MemberExpression node)
|
||||
{
|
||||
if (_findExp == node) return _replaceExp;
|
||||
return base.VisitMember(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract partial class Select0Provider<TSelect, T1> : Select0Provider, ISelect0<TSelect, T1> where TSelect : class
|
||||
|
@ -64,11 +64,12 @@ namespace FreeSql.Internal.CommonProvider
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<TTuple> ToList<TTuple>(string field)
|
||||
public List<TTuple> ToList<TTuple>(string field) => ToListQfPrivate<TTuple>(this.ToSql(field), field);
|
||||
public List<TTuple> ToListQfPrivate<TTuple>(string sql, string field)
|
||||
{
|
||||
var ret = new List<TTuple>();
|
||||
if (_cancel?.Invoke() == true) return ret;
|
||||
var sql = this.ToSql(field);
|
||||
if (string.IsNullOrEmpty(sql)) return ret;
|
||||
var dbParms = _params.ToArray();
|
||||
var type = typeof(TTuple);
|
||||
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
|
||||
@ -394,15 +395,6 @@ namespace FreeSql.Internal.CommonProvider
|
||||
return ToListMrPrivate<TReturn>(sql, af, otherData);
|
||||
}
|
||||
protected List<TReturn> ToListMapReader<TReturn>(ReadAnonymousTypeAfInfo af) => ToListMapReaderPrivate<TReturn>(af, null);
|
||||
protected ReadAnonymousTypeAfInfo GetExpressionField(Expression newexp, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
|
||||
{
|
||||
var map = new ReadAnonymousTypeInfo();
|
||||
var field = new StringBuilder();
|
||||
var index = fieldAlias == FieldAliasOptions.AsProperty ? CommonExpression.ReadAnonymousFieldAsCsName : 0;
|
||||
|
||||
_commonExpression.ReadAnonymousField(_tables, field, map, ref index, newexp, this, null, _whereGlobalFilter, null, null, true);
|
||||
return new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null);
|
||||
}
|
||||
static ConcurrentDictionary<string, GetAllFieldExpressionTreeInfo> _dicGetAllFieldExpressionTree = new ConcurrentDictionary<string, GetAllFieldExpressionTreeInfo>();
|
||||
public class GetAllFieldExpressionTreeInfo
|
||||
{
|
||||
@ -771,12 +763,41 @@ namespace FreeSql.Internal.CommonProvider
|
||||
|
||||
protected double InternalAvg(Expression exp)
|
||||
{
|
||||
var list = this.ToList<double>($"avg({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}");
|
||||
return list.Sum() / list.Count;
|
||||
var field = $"avg({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}";
|
||||
if (_limit <= 0 && _skip <= 0)
|
||||
{
|
||||
var list = this.ToList<double>(field);
|
||||
return list.Sum() / list.Count;
|
||||
}
|
||||
|
||||
var sql = GetNestSelectSql(exp, field, ToSql);
|
||||
var list2 = ToListQfPrivate<double>(sql, field);
|
||||
return list2.Sum() / list2.Count;
|
||||
}
|
||||
protected TMember InternalMax<TMember>(Expression exp)
|
||||
{
|
||||
var field = $"max({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}";
|
||||
if (_limit <= 0 && _skip <= 0) return this.ToList<TMember>(field).Max();
|
||||
|
||||
var sql = GetNestSelectSql(exp, field, ToSql);
|
||||
return ToListQfPrivate<TMember>(sql, field).Max();
|
||||
}
|
||||
protected TMember InternalMin<TMember>(Expression exp)
|
||||
{
|
||||
var field = $"min({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}";
|
||||
if (_limit <= 0 && _skip <= 0) return this.ToList<TMember>(field).Min();
|
||||
|
||||
var sql = GetNestSelectSql(exp, field, ToSql);
|
||||
return ToListQfPrivate<TMember>(sql, field).Min();
|
||||
}
|
||||
protected decimal InternalSum(Expression exp)
|
||||
{
|
||||
var field = $"sum({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}";
|
||||
if (_limit <= 0 && _skip <= 0) return this.ToList<decimal>(field).Sum();
|
||||
|
||||
var sql = GetNestSelectSql(exp, field, ToSql);
|
||||
return ToListQfPrivate<decimal>(sql, field).Sum();
|
||||
}
|
||||
protected TMember InternalMax<TMember>(Expression exp) => this.ToList<TMember>($"max({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}").Max();
|
||||
protected TMember InternalMin<TMember>(Expression exp) => this.ToList<TMember>($"min({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}").Min();
|
||||
protected decimal InternalSum(Expression exp) => this.ToList<decimal>($"sum({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}").Sum();
|
||||
|
||||
public ISelectGrouping<TKey, TValue> InternalGroupBy<TKey, TValue>(Expression columns)
|
||||
{
|
||||
@ -829,71 +850,6 @@ namespace FreeSql.Internal.CommonProvider
|
||||
return this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null)} DESC");
|
||||
}
|
||||
|
||||
class FindAllMemberExpressionVisitor : ExpressionVisitor
|
||||
{
|
||||
public List<NativeTuple<MemberExpression, ColumnInfo>> Result { get; set; } = new List<NativeTuple<MemberExpression, ColumnInfo>>();
|
||||
Select0Provider _select;
|
||||
public FindAllMemberExpressionVisitor(Select0Provider select) => _select = select;
|
||||
|
||||
protected override Expression VisitMember(MemberExpression node)
|
||||
{
|
||||
var exps = new Stack<Expression>();
|
||||
Expression exp = node;
|
||||
while (exp != null)
|
||||
{
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.Parameter:
|
||||
exps.Push(exp);
|
||||
exp = null;
|
||||
continue;
|
||||
case ExpressionType.MemberAccess:
|
||||
exps.Push(exp);
|
||||
exp = (exp as MemberExpression)?.Expression;
|
||||
continue;
|
||||
}
|
||||
return base.VisitMember(node);
|
||||
}
|
||||
if (exps.Any() == false) return base.VisitMember(node);
|
||||
var firstExp = exps.Pop() as ParameterExpression;
|
||||
if (firstExp == null) return base.VisitMember(node);
|
||||
var tb = _select._tables.Find(a => a.Parameter == firstExp)?.Table;
|
||||
if (tb == null) return base.VisitMember(node);
|
||||
|
||||
while (exps.Any())
|
||||
{
|
||||
var memExp = exps.Pop() as MemberExpression;
|
||||
if (tb.ColumnsByCs.TryGetValue(memExp.Member.Name, out var trycol) && exps.Any() == false)
|
||||
{
|
||||
Result.Add(NativeTuple.Create(node, trycol));
|
||||
return node;
|
||||
}
|
||||
if (tb.Properties.ContainsKey(memExp.Member.Name))
|
||||
{
|
||||
tb = _select._commonUtils.GetTableByEntity(memExp.Type);
|
||||
if (tb == null) return base.VisitMember(node);
|
||||
}
|
||||
}
|
||||
return base.VisitMember(node);
|
||||
}
|
||||
}
|
||||
class ReplaceMemberExpressionVisitor : ExpressionVisitor
|
||||
{
|
||||
Expression _findExp;
|
||||
Expression _replaceExp;
|
||||
public Expression Replace(Expression exp, Expression find, Expression replace) // object repval)
|
||||
{
|
||||
_findExp = find;
|
||||
_replaceExp = replace;
|
||||
//_replaceExp = Expression.Constant(repval, find.Type);
|
||||
return this.Visit(exp);
|
||||
}
|
||||
protected override Expression VisitMember(MemberExpression node)
|
||||
{
|
||||
if (_findExp == node) return _replaceExp;
|
||||
return base.VisitMember(node);
|
||||
}
|
||||
}
|
||||
public List<TReturn> InternalToList<TReturn>(Expression select)
|
||||
{
|
||||
var map = new ReadAnonymousTypeInfo();
|
||||
@ -1087,34 +1043,7 @@ namespace FreeSql.Internal.CommonProvider
|
||||
var af = new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null);
|
||||
if (GetTableRuleUnions().Count <= 1) return this.ToListMapReader<TReturn>(af).FirstOrDefault();
|
||||
|
||||
var affield = af.field;
|
||||
var allMemExps = new FindAllMemberExpressionVisitor(this);
|
||||
allMemExps.Visit(select);
|
||||
field.Clear();
|
||||
var fieldAlias = new Dictionary<string, bool>();
|
||||
var fieldReplaced = new Dictionary<string, bool>();
|
||||
foreach (var memExp in allMemExps.Result)
|
||||
{
|
||||
var gef = GetExpressionField(memExp.Item1, FieldAliasOptions.AsProperty);
|
||||
var geffield = gef.field;
|
||||
if (fieldReplaced.ContainsKey(geffield)) continue;
|
||||
fieldReplaced.Add(geffield, true);
|
||||
|
||||
field.Append(", ").Append(gef.field);
|
||||
if (fieldAlias.ContainsKey(memExp.Item2.Attribute.Name))
|
||||
{
|
||||
field.Append(_commonUtils.FieldAsAlias($"aas{fieldAlias.Count}"));
|
||||
affield = affield.Replace(geffield, $"ftba.aas{fieldAlias.Count}");
|
||||
}
|
||||
else
|
||||
{
|
||||
fieldAlias.Add(memExp.Item2.Attribute.Name, true);
|
||||
affield = affield.Replace(geffield, $"ftba.{string.Join(".", geffield.Split('.').Skip(1))}");
|
||||
}
|
||||
}
|
||||
|
||||
var sql = this.ToSql(field.Remove(0, 2).ToString());
|
||||
sql = $"{_select} {affield} FROM ( \r\n {sql.Replace("\r\n", "\r\n ")}\r\n) ftba";
|
||||
var sql = GetNestSelectSql(select, af.field, ToSql);
|
||||
return ToListMrPrivate<TReturn>(sql, af, null).FirstOrDefault();
|
||||
}
|
||||
finally
|
||||
@ -1173,11 +1102,12 @@ namespace FreeSql.Internal.CommonProvider
|
||||
return ret;
|
||||
}
|
||||
|
||||
async public Task<List<TTuple>> ToListAsync<TTuple>(string field, CancellationToken cancellationToken)
|
||||
public Task<List<TTuple>> ToListAsync<TTuple>(string field, CancellationToken cancellationToken) => ToListQfPrivateAsync<TTuple>(this.ToSql(field), field, cancellationToken);
|
||||
async public Task<List<TTuple>> ToListQfPrivateAsync<TTuple>(string sql, string field, CancellationToken cancellationToken)
|
||||
{
|
||||
var ret = new List<TTuple>();
|
||||
if (_cancel?.Invoke() == true) return ret;
|
||||
var sql = this.ToSql(field);
|
||||
if (string.IsNullOrEmpty(sql)) return ret;
|
||||
var dbParms = _params.ToArray();
|
||||
var type = typeof(TTuple);
|
||||
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
|
||||
@ -1380,12 +1310,41 @@ namespace FreeSql.Internal.CommonProvider
|
||||
|
||||
async protected Task<double> InternalAvgAsync(Expression exp, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = await this.ToListAsync<double>($"avg({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}", cancellationToken);
|
||||
return list.Sum() / list.Count;
|
||||
var field = $"avg({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}";
|
||||
if (_limit <= 0 && _skip <= 0)
|
||||
{
|
||||
var list = await this.ToListAsync<double>(field, cancellationToken);
|
||||
return list.Sum() / list.Count;
|
||||
}
|
||||
|
||||
var sql = GetNestSelectSql(exp, field, ToSql);
|
||||
var list2 = await ToListQfPrivateAsync<double>(sql, field, cancellationToken);
|
||||
return list2.Sum() / list2.Count;
|
||||
}
|
||||
async protected Task<TMember> InternalMaxAsync<TMember>(Expression exp, CancellationToken cancellationToken)
|
||||
{
|
||||
var field = $"max({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}";
|
||||
if (_limit <= 0 && _skip <= 0) return (await this.ToListAsync<TMember>(field, cancellationToken)).Max();
|
||||
|
||||
var sql = GetNestSelectSql(exp, field, ToSql);
|
||||
return (await ToListQfPrivateAsync<TMember>(sql, field, cancellationToken)).Max();
|
||||
}
|
||||
async protected Task<TMember> InternalMinAsync<TMember>(Expression exp, CancellationToken cancellationToken)
|
||||
{
|
||||
var field = $"min({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}";
|
||||
if (_limit <= 0 && _skip <= 0) return (await this.ToListAsync<TMember>(field, cancellationToken)).Min();
|
||||
|
||||
var sql = GetNestSelectSql(exp, field, ToSql);
|
||||
return (await ToListQfPrivateAsync<TMember>(sql, field, cancellationToken)).Min();
|
||||
}
|
||||
async protected Task<decimal> InternalSumAsync(Expression exp, CancellationToken cancellationToken)
|
||||
{
|
||||
var field = $"sum({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}";
|
||||
if (_limit <= 0 && _skip <= 0) return (await this.ToListAsync<decimal>(field, cancellationToken)).Sum();
|
||||
|
||||
var sql = GetNestSelectSql(exp, field, ToSql);
|
||||
return (await ToListQfPrivateAsync<decimal>(sql, field, cancellationToken)).Sum();
|
||||
}
|
||||
async protected Task<TMember> InternalMaxAsync<TMember>(Expression exp, CancellationToken cancellationToken) => (await this.ToListAsync<TMember>($"max({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}", cancellationToken)).Max();
|
||||
async protected Task<TMember> InternalMinAsync<TMember>(Expression exp, CancellationToken cancellationToken) => (await this.ToListAsync<TMember>($"min({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}", cancellationToken)).Min();
|
||||
async protected Task<decimal> InternalSumAsync(Expression exp, CancellationToken cancellationToken) => (await this.ToListAsync<decimal>($"sum({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}", cancellationToken)).Sum();
|
||||
|
||||
static ConcurrentDictionary<Type, MethodInfo[]> _dicGetMethodsByName = new ConcurrentDictionary<Type, MethodInfo[]>();
|
||||
async protected Task<List<TReturn>> InternalToListAsync<TReturn>(Expression select, CancellationToken cancellationToken)
|
||||
@ -1577,34 +1536,7 @@ namespace FreeSql.Internal.CommonProvider
|
||||
var af = new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null);
|
||||
if (GetTableRuleUnions().Count <= 1) return (await this.ToListMapReaderAsync<TReturn>(af, cancellationToken)).FirstOrDefault();
|
||||
|
||||
var affield = af.field;
|
||||
var allMemExps = new FindAllMemberExpressionVisitor(this);
|
||||
allMemExps.Visit(select);
|
||||
field.Clear();
|
||||
var fieldAlias = new Dictionary<string, bool>();
|
||||
var fieldReplaced = new Dictionary<string, bool>();
|
||||
foreach (var memExp in allMemExps.Result)
|
||||
{
|
||||
var gef = GetExpressionField(memExp.Item1, FieldAliasOptions.AsProperty);
|
||||
var geffield = gef.field;
|
||||
if (fieldReplaced.ContainsKey(geffield)) continue;
|
||||
fieldReplaced.Add(geffield, true);
|
||||
|
||||
field.Append(", ").Append(gef.field);
|
||||
if (fieldAlias.ContainsKey(memExp.Item2.Attribute.Name))
|
||||
{
|
||||
field.Append(_commonUtils.FieldAsAlias($"aas{fieldAlias.Count}"));
|
||||
affield = affield.Replace(geffield, $"ftba.aas{fieldAlias.Count}");
|
||||
}
|
||||
else
|
||||
{
|
||||
fieldAlias.Add(memExp.Item2.Attribute.Name, true);
|
||||
affield = affield.Replace(geffield, $"ftba.{string.Join(".", geffield.Split('.').Skip(1))}");
|
||||
}
|
||||
}
|
||||
|
||||
var sql = this.ToSql(field.Remove(0, 2).ToString());
|
||||
sql = $"{_select} {affield} FROM ( \r\n {sql.Replace("\r\n", "\r\n ")}\r\n) ftba";
|
||||
var sql = GetNestSelectSql(select, af.field, ToSql);
|
||||
return (await ToListMrPrivateAsync<TReturn>(sql, af, null, cancellationToken)).FirstOrDefault();
|
||||
}
|
||||
finally
|
||||
|
Loading…
x
Reference in New Issue
Block a user