ExpressionTree 优化告一段落

This commit is contained in:
28810
2019-01-19 15:21:04 +08:00
parent 0068474992
commit 56d79c9696
5 changed files with 399 additions and 273 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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[] {