mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-06-19 12:28:15 +08:00
ExpressionTree 优化告一段落
This commit is contained in:
@ -2,11 +2,13 @@
|
||||
using SafeObjectPool;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
abstract partial class AdoProvider : IAdo {
|
||||
@ -62,15 +64,21 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
if (isThrowException) throw e;
|
||||
}
|
||||
|
||||
internal static ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>> dicQueryTypeGetProperties = new ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>>();
|
||||
public List<T> Query<T>(string cmdText, object parms = null) => Query<T>(CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
|
||||
public List<T> Query<T>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
var names = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
|
||||
var ret = new List<T>();
|
||||
var type = typeof(T);
|
||||
int[] indexes = null;
|
||||
var props = dicQueryTypeGetProperties.GetOrAdd(type, k => type.GetProperties().ToDictionary(a => a.Name, a => a, StringComparer.CurrentCultureIgnoreCase));
|
||||
ExecuteReader(dr => {
|
||||
if (names.Any() == false)
|
||||
for (var a = 0; a < dr.FieldCount; a++) names.Add(dr.GetName(a), a);
|
||||
ret.Add((T)Utils.ExecuteArrayRowReadClassOrTuple(type, names, dr, 0).Value);
|
||||
if (indexes == null) {
|
||||
var idxs = new List<int>();
|
||||
for (var a = 0; a < dr.FieldCount; a++)
|
||||
if (props.ContainsKey(dr.GetName(a))) idxs.Add(a);
|
||||
indexes = idxs.ToArray();
|
||||
}
|
||||
ret.Add((T)Utils.ExecuteArrayRowReadClassOrTuple(type, indexes, dr, 0).Value);
|
||||
}, cmdType, cmdText, cmdParms);
|
||||
return ret;
|
||||
}
|
||||
|
@ -11,13 +11,18 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
partial class AdoProvider {
|
||||
public Task<List<T>> QueryAsync<T>(string cmdText, object parms = null) => QueryAsync<T>(CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
|
||||
async public Task<List<T>> QueryAsync<T>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
var names = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
|
||||
var ret = new List<T>();
|
||||
var type = typeof(T);
|
||||
int[] indexes = null;
|
||||
var props = dicQueryTypeGetProperties.GetOrAdd(type, k => type.GetProperties().ToDictionary(a => a.Name, a => a, StringComparer.CurrentCultureIgnoreCase));
|
||||
await ExecuteReaderAsync(dr => {
|
||||
if (names.Any() == false)
|
||||
for (var a = 0; a < dr.FieldCount; a++) names.Add(dr.GetName(a), a);
|
||||
ret.Add((T)Utils.ExecuteArrayRowReadClassOrTuple(type, names, dr, 0).Value);
|
||||
if (indexes == null) {
|
||||
var idxs = new List<int>();
|
||||
for (var a = 0; a < dr.FieldCount; a++)
|
||||
if (props.ContainsKey(dr.GetName(a))) idxs.Add(a);
|
||||
indexes = idxs.ToArray();
|
||||
}
|
||||
ret.Add((T)Utils.ExecuteArrayRowReadClassOrTuple(type, indexes, dr, 0).Value);
|
||||
return Task.CompletedTask;
|
||||
}, cmdType, cmdText, cmdParms);
|
||||
return ret;
|
||||
|
@ -271,6 +271,7 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
var dicfield = new Dictionary<string, bool>();
|
||||
var tb = _tables.First();
|
||||
var index = 0;
|
||||
var otherindex = 0;
|
||||
var ps = _tables.First().Table.Properties;
|
||||
foreach (var prop in ps.Values) {
|
||||
if (tb.Table.ColumnsByCs.TryGetValue(prop.Name, out var col)) { //普通字段
|
||||
@ -289,6 +290,7 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
var quoteName = _commonUtils.QuoteSqlName(col2.Attribute.Name);
|
||||
field.Append(_commonUtils.QuoteReadColumn(col2.CsType, $"{tb2.Alias}.{quoteName}"));
|
||||
++index;
|
||||
++otherindex;
|
||||
if (dicfield.ContainsKey(quoteName)) field.Append(" as").Append(index);
|
||||
else dicfield.Add(quoteName, true);
|
||||
}
|
||||
@ -297,7 +299,8 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
var propGetSetMethod = prop.GetSetMethod();
|
||||
Expression readExpAssign = null; //加速缓存
|
||||
if (prop.PropertyType.IsArray) readExpAssign = Expression.New(Utils.RowInfo.Constructor,
|
||||
Expression.Call(Utils.MethodGetDataReaderValue, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Call(rowExp, Utils.MethodDataReaderGetValue, dataIndexExp) }),
|
||||
Utils.GetDataReaderValueBlockExpression(prop.PropertyType, Expression.Call(rowExp, Utils.MethodDataReaderGetValue, dataIndexExp)),
|
||||
//Expression.Call(Utils.MethodGetDataReaderValue, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Call(rowExp, Utils.MethodDataReaderGetValue, dataIndexExp) }),
|
||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
||||
);
|
||||
else {
|
||||
@ -305,27 +308,29 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
if (proptypeGeneric.FullName.StartsWith("System.Nullable`1[")) proptypeGeneric = proptypeGeneric.GenericTypeArguments.First();
|
||||
if (proptypeGeneric.IsEnum ||
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple.ContainsKey(proptypeGeneric)) readExpAssign = Expression.New(Utils.RowInfo.Constructor,
|
||||
Expression.Call(Utils.MethodGetDataReaderValue, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Call(rowExp, Utils.MethodDataReaderGetValue, dataIndexExp) }),
|
||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
||||
Utils.GetDataReaderValueBlockExpression(prop.PropertyType, Expression.Call(rowExp, Utils.MethodDataReaderGetValue, dataIndexExp)),
|
||||
//Expression.Call(Utils.MethodGetDataReaderValue, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Call(rowExp, Utils.MethodDataReaderGetValue, dataIndexExp) }),
|
||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
||||
);
|
||||
else {
|
||||
readExpAssign = Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Constant(null, typeof(Dictionary<string, int>)), rowExp, dataIndexExp });
|
||||
readExpAssign = Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp });
|
||||
}
|
||||
}
|
||||
blockExp.AddRange(new Expression[] {
|
||||
//以下注释部分为【严格读取】,会损失一点性能
|
||||
//Expression.IfThen(Expression.Not(Expression.And(
|
||||
// Expression.NotEqual(namesExp, Expression.Constant(null)),
|
||||
// Expression.Not(Expression.Call(namesExp, namesExp.Type.GetMethod("TryGetValue"), Expression.Constant(prop.Name), tryidxExp)))),
|
||||
// Expression.Block(
|
||||
Expression.Assign(readExp, readExpAssign),
|
||||
Expression.IfThen(Expression.GreaterThan(readExpDataIndex, dataIndexExp),
|
||||
Expression.Assign(dataIndexExp, readExpDataIndex)),
|
||||
Expression.IfThenElse(Expression.Equal(readExpValue, Expression.Constant(null)),
|
||||
Expression.Call(retExp, propGetSetMethod, Expression.Default(prop.PropertyType)),
|
||||
Expression.Call(retExp, propGetSetMethod, Expression.Convert(readExpValue, prop.PropertyType)))
|
||||
// )
|
||||
//)
|
||||
Expression.Assign(readExp, readExpAssign),
|
||||
Expression.IfThen(Expression.GreaterThan(readExpDataIndex, dataIndexExp),
|
||||
Expression.Assign(dataIndexExp, readExpDataIndex)),
|
||||
Expression.IfThenElse(Expression.Equal(readExpValue, Expression.Constant(null)),
|
||||
Expression.Call(retExp, propGetSetMethod, Expression.Default(prop.PropertyType)),
|
||||
Expression.Call(retExp, propGetSetMethod, Expression.Convert(readExpValue, prop.PropertyType)))
|
||||
});
|
||||
}
|
||||
if (otherindex == 0) { //不读导航属性,优化单表读取性能
|
||||
blockExp.Clear();
|
||||
blockExp.AddRange(new Expression[] {
|
||||
Expression.Assign(dataIndexExp, Expression.Constant(0)),
|
||||
Expression.Assign(readExp, Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(type), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp })),
|
||||
Expression.Assign(retExp, Expression.Convert(readExpValue, type))
|
||||
});
|
||||
}
|
||||
blockExp.AddRange(new Expression[] {
|
||||
|
Reference in New Issue
Block a user