fix:修复 Group 查询不支持 aot 问题

perf:优化非 aot 下分组查询性能(减少反射)
This commit is contained in:
Linlccc
2025-07-18 16:40:38 +08:00
parent 58bf5c1fda
commit e1f81c4bc7
3 changed files with 106 additions and 108 deletions

View File

@@ -5,6 +5,7 @@ using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
@@ -87,6 +88,83 @@ namespace FreeSql.Internal.CommonProvider
public abstract string ToSqlBase(string field = null);
public abstract void AsTableBase(Func<Type, string, string> tableRule);
internal virtual List<TReturn> ToListMrPrivate<TReturn>(string sql, ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData)
{
var ret = new List<TReturn>();
if (_cancel?.Invoke() == true) return ret;
var dbParms = _params.ToArray();
var type = typeof(TReturn);
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var retCount = 0;
Exception exception = null;
try
{
_orm.Ado.ExecuteReader(_connection, _transaction, fetch =>
{
var index = -1;
ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, fetch.Object, ref index, false, null, retCount, af.fillIncludeMany, af.fillSubSelectMany));
if (otherData != null)
foreach (var other in otherData)
other.retlist.Add(_commonExpression.ReadAnonymous(other.read, fetch.Object, ref index, false, null, retCount, null, null));
retCount++;
}, CommandType.Text, sql, _commandTimeout, dbParms);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
_trackToList?.Invoke(ret);
return ret;
}
#region async
#if !net40
internal virtual async Task<List<TReturn>> ToListMrPrivateAsync<TReturn>(string sql, ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData, CancellationToken cancellationToken)
{
var ret = new List<TReturn>();
if (_cancel?.Invoke() == true) return ret;
var dbParms = _params.ToArray();
var type = typeof(TReturn);
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var retCount = 0;
Exception exception = null;
try
{
await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, fetch =>
{
var index = -1;
ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, fetch.Object, ref index, false, null, retCount, af.fillIncludeMany, af.fillSubSelectMany));
if (otherData != null)
foreach (var other in otherData)
other.retlist.Add(_commonExpression.ReadAnonymous(other.read, fetch.Object, ref index, false, null, retCount, null, null));
retCount++;
return Task.FromResult(false);
}, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
_trackToList?.Invoke(ret);
return ret;
}
#endif
#endregion
public static void CopyData(Select0Provider from, Select0Provider to, ReadOnlyCollection<ParameterExpression> lambParms)
{
if (to == null) return;

View File

@@ -343,41 +343,10 @@ namespace FreeSql.Internal.CommonProvider
return ret;
}
internal List<TReturn> ToListMrPrivate<TReturn>(string sql, ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData)
internal override List<TReturn> ToListMrPrivate<TReturn>(string sql, ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData)
{
var ret = new List<TReturn>();
if (_cancel?.Invoke() == true) return ret;
var dbParms = _params.ToArray();
var type = typeof(TReturn);
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var retCount = 0;
Exception exception = null;
try
{
_orm.Ado.ExecuteReader(_connection, _transaction, fetch =>
{
var index = -1;
ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, fetch.Object, ref index, false, null, retCount, af.fillIncludeMany, af.fillSubSelectMany));
if (otherData != null)
foreach (var other in otherData)
other.retlist.Add(_commonExpression.ReadAnonymous(other.read, fetch.Object, ref index, false, null, retCount, null, null));
retCount++;
}, CommandType.Text, sql, _commandTimeout, dbParms);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
if (typeof(TReturn) == typeof(T1))
foreach (var include in _includeToList) include?.Invoke(ret);
_trackToList?.Invoke(ret);
var ret = base.ToListMrPrivate<TReturn>(sql, af, otherData);
if (typeof(TReturn) == typeof(T1)) foreach (var include in _includeToList) include?.Invoke(ret);
return ret;
}
internal List<TReturn> ToListMapReaderPrivate<TReturn>(ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData)
@@ -1377,42 +1346,10 @@ namespace FreeSql.Internal.CommonProvider
return ret;
}
async internal Task<List<TReturn>> ToListMrPrivateAsync<TReturn>(string sql, ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData, CancellationToken cancellationToken)
internal override async Task<List<TReturn>> ToListMrPrivateAsync<TReturn>(string sql, ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData, CancellationToken cancellationToken)
{
var ret = new List<TReturn>();
if (_cancel?.Invoke() == true) return ret;
var dbParms = _params.ToArray();
var type = typeof(TReturn);
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var retCount = 0;
Exception exception = null;
try
{
await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, fetch =>
{
var index = -1;
ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, fetch.Object, ref index, false, null, retCount, af.fillIncludeMany, af.fillSubSelectMany));
if (otherData != null)
foreach (var other in otherData)
other.retlist.Add(_commonExpression.ReadAnonymous(other.read, fetch.Object, ref index, false, null, retCount, null, null));
retCount++;
return Task.FromResult(false);
}, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
if (typeof(TReturn) == typeof(T1))
foreach (var include in _includeToListAsync) await include?.Invoke(ret, cancellationToken);
_trackToList?.Invoke(ret);
var ret = await base.ToListMrPrivateAsync<TReturn>(sql, af, otherData, cancellationToken);
if (typeof(TReturn) == typeof(T1)) foreach (var include in _includeToListAsync) await include?.Invoke(ret, cancellationToken);
return ret;
}
internal Task<List<TReturn>> ToListMapReaderPrivateAsync<TReturn>(ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData, CancellationToken cancellationToken)

View File

@@ -156,34 +156,6 @@ namespace FreeSql.Internal.CommonProvider
var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) });
method.Invoke(_select, new object[] { isDescending ? $"{sql} DESC" : sql, null });
}
public object InternalToList(Expression select, Type elementType)
{
var map = new ReadAnonymousTypeInfo();
var field = new StringBuilder();
var index = 0;
_comonExp.ReadAnonymousField(null, _select._tableRule, field, map, ref index, select, _select, this, null, null, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = elementType;
var method = _select.GetType().GetMethod("ToListMrPrivate", BindingFlags.Instance | BindingFlags.NonPublic);
method = method.MakeGenericMethod(elementType);
var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
return method.Invoke(_select, new object[] { InternalToSql(fieldSql), new ReadAnonymousTypeAfInfo(map, fieldSql), null });
}
public IEnumerable<KeyValuePair<object, object>> InternalToKeyValuePairs(Expression elementSelector, Type elementType)
{
var map = new ReadAnonymousTypeInfo();
var field = new StringBuilder();
var index = 0;
_comonExp.ReadAnonymousField(null, _select._tableRule, field, map, ref index, elementSelector, _select, this, null, null, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = elementType;
var method = _select.GetType().GetMethod("ToListMrPrivate", BindingFlags.Instance | BindingFlags.NonPublic);
method = method.MakeGenericMethod(elementType);
var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
var otherAf = new ReadAnonymousTypeOtherInfo(_field, _map, new List<object>());
var values = method.Invoke(_select, new object[] { InternalToSql($"{fieldSql}{_field}"), new ReadAnonymousTypeAfInfo(map, fieldSql), new[] { otherAf } }) as IList;
return otherAf.retlist.Select((a, b) => new KeyValuePair<object, object>(a, values[b]));
}
public string InternalToSql(Expression select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
{
var map = new ReadAnonymousTypeInfo();
@@ -214,8 +186,7 @@ namespace FreeSql.Internal.CommonProvider
_select._skip = _groupBySkip;
break;
}
var method = _select.GetType().GetMethod("ToSql", new[] { typeof(string) });
var sql = method.Invoke(_select, new object[] { field }) as string;
var sql = _select.ToSqlBase(field);
if (isNestedPageSql == false)
{
_select._limit = 0;
@@ -337,13 +308,29 @@ namespace FreeSql.Internal.CommonProvider
public TReturn First<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => ToList<TReturn>(select).FirstOrDefault();
public List<TReturn> ToList<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select)
{
var map = new ReadAnonymousTypeInfo();
var field = new StringBuilder();
var index = 0;
_lambdaParameter = select?.Parameters[0];
return InternalToList(select, typeof(TReturn)) as List<TReturn>;
_comonExp.ReadAnonymousField(null, _select._tableRule, field, map, ref index, select, _select, this, null, null, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn);
var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
return _select.ToListMrPrivate<TReturn>(InternalToSql(fieldSql), new ReadAnonymousTypeAfInfo(map, fieldSql), null);
}
public Dictionary<TKey, TElement> ToDictionary<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector)
{
var map = new ReadAnonymousTypeInfo();
var field = new StringBuilder();
var index = 0;
_lambdaParameter = elementSelector?.Parameters[0];
return InternalToKeyValuePairs(elementSelector, typeof(TElement)).ToDictionary(a => (TKey)a.Key, a => (TElement)a.Value);
_comonExp.ReadAnonymousField(null, _select._tableRule, field, map, ref index, elementSelector, _select, this, null, null, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TElement);
var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
var otherAf = new ReadAnonymousTypeOtherInfo(_field, _map, new List<object>());
var values = _select.ToListMrPrivate<TElement>(InternalToSql($"{fieldSql}{_field}"), new ReadAnonymousTypeAfInfo(map, fieldSql), new[] { otherAf });
return otherAf.retlist.Select((a, b) => new KeyValuePair<TKey, TElement>((TKey)a, values[b])).ToDictionary(a=>a.Key,a=>a.Value);
}
#if net40
@@ -360,12 +347,10 @@ namespace FreeSql.Internal.CommonProvider
_lambdaParameter = select?.Parameters[0];
_comonExp.ReadAnonymousField(null, _select._tableRule, field, map, ref index, select, _select, this, null, null, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn);
var method = _select.GetType().GetMethod("ToListMrPrivateAsync", BindingFlags.Instance | BindingFlags.NonPublic);
method = method.MakeGenericMethod(typeof(TReturn));
var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
return method.Invoke(_select, new object[] { InternalToSql(fieldSql), new ReadAnonymousTypeAfInfo(map, fieldSql), null, cancellationToken }) as Task<List<TReturn>>;
return _select.ToListMrPrivateAsync<TReturn>(InternalToSql(fieldSql), new ReadAnonymousTypeAfInfo(map, fieldSql), null, cancellationToken);
}
async public Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector, CancellationToken cancellationToken = default)
public async Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector, CancellationToken cancellationToken = default)
{
var map = new ReadAnonymousTypeInfo();
var field = new StringBuilder();
@@ -374,11 +359,9 @@ namespace FreeSql.Internal.CommonProvider
_lambdaParameter = elementSelector?.Parameters[0];
_comonExp.ReadAnonymousField(null, _select._tableRule, field, map, ref index, elementSelector, _select, this, null, null, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TElement);
var method = _select.GetType().GetMethod("ToListMrPrivateAsync", BindingFlags.Instance | BindingFlags.NonPublic);
method = method.MakeGenericMethod(typeof(TElement));
var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
var otherAf = new ReadAnonymousTypeOtherInfo(_field, _map, new List<object>());
var values = await (method.Invoke(_select, new object[] { InternalToSql($"{fieldSql}{_field}"), new ReadAnonymousTypeAfInfo(map, fieldSql), new[] { otherAf }, cancellationToken }) as Task<List<TElement>>);
var values = await _select.ToListMrPrivateAsync<TElement>(InternalToSql($"{fieldSql}{_field}"), new ReadAnonymousTypeAfInfo(map, fieldSql), new[] { otherAf }, cancellationToken);
return otherAf.retlist.Select((a, b) => new KeyValuePair<TKey, TElement>((TKey)a, values[b])).ToDictionary(a => a.Key, a => a.Value);
}
#endif