mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 02:32:50 +08:00
ExpressionTree 优化告一段落
This commit is contained in:
parent
0068474992
commit
56d79c9696
@ -2,11 +2,13 @@
|
|||||||
using SafeObjectPool;
|
using SafeObjectPool;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace FreeSql.Internal.CommonProvider {
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
abstract partial class AdoProvider : IAdo {
|
abstract partial class AdoProvider : IAdo {
|
||||||
@ -62,15 +64,21 @@ namespace FreeSql.Internal.CommonProvider {
|
|||||||
if (isThrowException) throw e;
|
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>(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) {
|
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 ret = new List<T>();
|
||||||
var type = typeof(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 => {
|
ExecuteReader(dr => {
|
||||||
if (names.Any() == false)
|
if (indexes == null) {
|
||||||
for (var a = 0; a < dr.FieldCount; a++) names.Add(dr.GetName(a), a);
|
var idxs = new List<int>();
|
||||||
ret.Add((T)Utils.ExecuteArrayRowReadClassOrTuple(type, names, dr, 0).Value);
|
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);
|
}, cmdType, cmdText, cmdParms);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,18 @@ namespace FreeSql.Internal.CommonProvider {
|
|||||||
partial class AdoProvider {
|
partial class AdoProvider {
|
||||||
public Task<List<T>> QueryAsync<T>(string cmdText, object parms = null) => QueryAsync<T>(CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
|
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) {
|
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 ret = new List<T>();
|
||||||
var type = typeof(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 => {
|
await ExecuteReaderAsync(dr => {
|
||||||
if (names.Any() == false)
|
if (indexes == null) {
|
||||||
for (var a = 0; a < dr.FieldCount; a++) names.Add(dr.GetName(a), a);
|
var idxs = new List<int>();
|
||||||
ret.Add((T)Utils.ExecuteArrayRowReadClassOrTuple(type, names, dr, 0).Value);
|
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;
|
return Task.CompletedTask;
|
||||||
}, cmdType, cmdText, cmdParms);
|
}, cmdType, cmdText, cmdParms);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -271,6 +271,7 @@ namespace FreeSql.Internal.CommonProvider {
|
|||||||
var dicfield = new Dictionary<string, bool>();
|
var dicfield = new Dictionary<string, bool>();
|
||||||
var tb = _tables.First();
|
var tb = _tables.First();
|
||||||
var index = 0;
|
var index = 0;
|
||||||
|
var otherindex = 0;
|
||||||
var ps = _tables.First().Table.Properties;
|
var ps = _tables.First().Table.Properties;
|
||||||
foreach (var prop in ps.Values) {
|
foreach (var prop in ps.Values) {
|
||||||
if (tb.Table.ColumnsByCs.TryGetValue(prop.Name, out var col)) { //普通字段
|
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);
|
var quoteName = _commonUtils.QuoteSqlName(col2.Attribute.Name);
|
||||||
field.Append(_commonUtils.QuoteReadColumn(col2.CsType, $"{tb2.Alias}.{quoteName}"));
|
field.Append(_commonUtils.QuoteReadColumn(col2.CsType, $"{tb2.Alias}.{quoteName}"));
|
||||||
++index;
|
++index;
|
||||||
|
++otherindex;
|
||||||
if (dicfield.ContainsKey(quoteName)) field.Append(" as").Append(index);
|
if (dicfield.ContainsKey(quoteName)) field.Append(" as").Append(index);
|
||||||
else dicfield.Add(quoteName, true);
|
else dicfield.Add(quoteName, true);
|
||||||
}
|
}
|
||||||
@ -297,7 +299,8 @@ namespace FreeSql.Internal.CommonProvider {
|
|||||||
var propGetSetMethod = prop.GetSetMethod();
|
var propGetSetMethod = prop.GetSetMethod();
|
||||||
Expression readExpAssign = null; //加速缓存
|
Expression readExpAssign = null; //加速缓存
|
||||||
if (prop.PropertyType.IsArray) readExpAssign = Expression.New(Utils.RowInfo.Constructor,
|
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))
|
Expression.Add(dataIndexExp, Expression.Constant(1))
|
||||||
);
|
);
|
||||||
else {
|
else {
|
||||||
@ -305,27 +308,29 @@ namespace FreeSql.Internal.CommonProvider {
|
|||||||
if (proptypeGeneric.FullName.StartsWith("System.Nullable`1[")) proptypeGeneric = proptypeGeneric.GenericTypeArguments.First();
|
if (proptypeGeneric.FullName.StartsWith("System.Nullable`1[")) proptypeGeneric = proptypeGeneric.GenericTypeArguments.First();
|
||||||
if (proptypeGeneric.IsEnum ||
|
if (proptypeGeneric.IsEnum ||
|
||||||
Utils.dicExecuteArrayRowReadClassOrTuple.ContainsKey(proptypeGeneric)) readExpAssign = Expression.New(Utils.RowInfo.Constructor,
|
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) }),
|
Utils.GetDataReaderValueBlockExpression(prop.PropertyType, Expression.Call(rowExp, Utils.MethodDataReaderGetValue, dataIndexExp)),
|
||||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
//Expression.Call(Utils.MethodGetDataReaderValue, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Call(rowExp, Utils.MethodDataReaderGetValue, dataIndexExp) }),
|
||||||
|
Expression.Add(dataIndexExp, Expression.Constant(1))
|
||||||
);
|
);
|
||||||
else {
|
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[] {
|
blockExp.AddRange(new Expression[] {
|
||||||
//以下注释部分为【严格读取】,会损失一点性能
|
Expression.Assign(readExp, readExpAssign),
|
||||||
//Expression.IfThen(Expression.Not(Expression.And(
|
Expression.IfThen(Expression.GreaterThan(readExpDataIndex, dataIndexExp),
|
||||||
// Expression.NotEqual(namesExp, Expression.Constant(null)),
|
Expression.Assign(dataIndexExp, readExpDataIndex)),
|
||||||
// Expression.Not(Expression.Call(namesExp, namesExp.Type.GetMethod("TryGetValue"), Expression.Constant(prop.Name), tryidxExp)))),
|
Expression.IfThenElse(Expression.Equal(readExpValue, Expression.Constant(null)),
|
||||||
// Expression.Block(
|
Expression.Call(retExp, propGetSetMethod, Expression.Default(prop.PropertyType)),
|
||||||
Expression.Assign(readExp, readExpAssign),
|
Expression.Call(retExp, propGetSetMethod, Expression.Convert(readExpValue, prop.PropertyType)))
|
||||||
Expression.IfThen(Expression.GreaterThan(readExpDataIndex, dataIndexExp),
|
});
|
||||||
Expression.Assign(dataIndexExp, readExpDataIndex)),
|
}
|
||||||
Expression.IfThenElse(Expression.Equal(readExpValue, Expression.Constant(null)),
|
if (otherindex == 0) { //不读导航属性,优化单表读取性能
|
||||||
Expression.Call(retExp, propGetSetMethod, Expression.Default(prop.PropertyType)),
|
blockExp.Clear();
|
||||||
Expression.Call(retExp, propGetSetMethod, Expression.Convert(readExpValue, prop.PropertyType)))
|
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[] {
|
blockExp.AddRange(new Expression[] {
|
||||||
|
@ -24,77 +24,78 @@ namespace FreeSql.Internal {
|
|||||||
static ConcurrentDictionary<string, TableInfo> _cacheGetTableByEntity = new ConcurrentDictionary<string, TableInfo>();
|
static ConcurrentDictionary<string, TableInfo> _cacheGetTableByEntity = new ConcurrentDictionary<string, TableInfo>();
|
||||||
internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) {
|
internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) {
|
||||||
if (entity.FullName.StartsWith("<>f__AnonymousType")) return null;
|
if (entity.FullName.StartsWith("<>f__AnonymousType")) return null;
|
||||||
if (_cacheGetTableByEntity.TryGetValue($"{common.DbName}-{entity.FullName}", out var trytb)) return trytb; //区分数据库类型缓存
|
return _cacheGetTableByEntity.GetOrAdd($"{common.DbName}-{entity.FullName}", key => { //区分数据库类型缓存
|
||||||
if (common.CodeFirst.GetDbInfo(entity) != null) return null;
|
if (common.CodeFirst.GetDbInfo(entity) != null) return null;
|
||||||
|
|
||||||
var tbattr = entity.GetCustomAttributes(typeof(TableAttribute), false).LastOrDefault() as TableAttribute;
|
var tbattr = entity.GetCustomAttributes(typeof(TableAttribute), false).LastOrDefault() as TableAttribute;
|
||||||
trytb = new TableInfo();
|
var trytb = new TableInfo();
|
||||||
trytb.Type = entity;
|
trytb.Type = entity;
|
||||||
trytb.Properties = entity.GetProperties().ToDictionary(a => a.Name, a => a, StringComparer.CurrentCultureIgnoreCase);
|
trytb.Properties = entity.GetProperties().ToDictionary(a => a.Name, a => a, StringComparer.CurrentCultureIgnoreCase);
|
||||||
trytb.CsName = entity.Name;
|
trytb.CsName = entity.Name;
|
||||||
trytb.DbName = (tbattr?.Name ?? entity.Name);
|
trytb.DbName = (tbattr?.Name ?? entity.Name);
|
||||||
trytb.DbOldName = tbattr?.OldName;
|
trytb.DbOldName = tbattr?.OldName;
|
||||||
if (common.CodeFirst.IsSyncStructureToLower) {
|
if (common.CodeFirst.IsSyncStructureToLower) {
|
||||||
trytb.DbName = trytb.DbName.ToLower();
|
trytb.DbName = trytb.DbName.ToLower();
|
||||||
trytb.DbOldName = trytb.DbOldName?.ToLower();
|
trytb.DbOldName = trytb.DbOldName?.ToLower();
|
||||||
}
|
}
|
||||||
trytb.SelectFilter = tbattr?.SelectFilter;
|
trytb.SelectFilter = tbattr?.SelectFilter;
|
||||||
foreach (var p in trytb.Properties.Values) {
|
foreach (var p in trytb.Properties.Values) {
|
||||||
var tp = common.CodeFirst.GetDbInfo(p.PropertyType);
|
var tp = common.CodeFirst.GetDbInfo(p.PropertyType);
|
||||||
//if (tp == null) continue;
|
//if (tp == null) continue;
|
||||||
var colattr = p.GetCustomAttributes(typeof(ColumnAttribute), false).LastOrDefault() as ColumnAttribute;
|
var colattr = p.GetCustomAttributes(typeof(ColumnAttribute), false).LastOrDefault() as ColumnAttribute;
|
||||||
if (tp == null && colattr == null) continue;
|
if (tp == null && colattr == null) continue;
|
||||||
if (colattr == null)
|
if (colattr == null)
|
||||||
colattr = new ColumnAttribute {
|
colattr = new ColumnAttribute {
|
||||||
Name = p.Name,
|
Name = p.Name,
|
||||||
DbType = tp.Value.dbtypeFull,
|
DbType = tp.Value.dbtypeFull,
|
||||||
IsIdentity = false,
|
IsIdentity = false,
|
||||||
IsNullable = tp.Value.isnullable ?? true,
|
IsNullable = tp.Value.isnullable ?? true,
|
||||||
IsPrimary = false,
|
IsPrimary = false,
|
||||||
|
};
|
||||||
|
if (string.IsNullOrEmpty(colattr.DbType)) colattr.DbType = tp?.dbtypeFull ?? "varchar(255)";
|
||||||
|
colattr.DbType = colattr.DbType.ToUpper();
|
||||||
|
|
||||||
|
if (tp != null && tp.Value.isnullable == null) colattr.IsNullable = tp.Value.dbtypeFull.Contains("NOT NULL") == false;
|
||||||
|
if (colattr.DbType?.Contains("NOT NULL") == true) colattr.IsNullable = false;
|
||||||
|
if (string.IsNullOrEmpty(colattr.Name)) colattr.Name = p.Name;
|
||||||
|
if (common.CodeFirst.IsSyncStructureToLower) colattr.Name = colattr.Name.ToLower();
|
||||||
|
|
||||||
|
if ((colattr.IsNullable == false || colattr.IsIdentity || colattr.IsPrimary) && colattr.DbType.Contains("NOT NULL") == false) {
|
||||||
|
colattr.IsNullable = false;
|
||||||
|
colattr.DbType += " NOT NULL";
|
||||||
|
}
|
||||||
|
if (colattr.IsNullable == true && colattr.DbType.Contains("NOT NULL")) colattr.DbType = colattr.DbType.Replace("NOT NULL", "");
|
||||||
|
colattr.DbType = Regex.Replace(colattr.DbType, @"\([^\)]+\)", m => {
|
||||||
|
var tmpLt = Regex.Replace(m.Groups[0].Value, @"\s", "");
|
||||||
|
if (tmpLt.Contains("CHAR")) tmpLt = tmpLt.Replace("CHAR", " CHAR");
|
||||||
|
if (tmpLt.Contains("BYTE")) tmpLt = tmpLt.Replace("BYTE", " BYTE");
|
||||||
|
return tmpLt;
|
||||||
|
});
|
||||||
|
colattr.DbDefautValue = trytb.Properties[p.Name].GetValue(Activator.CreateInstance(trytb.Type));
|
||||||
|
if (colattr.DbDefautValue == null) colattr.DbDefautValue = tp?.defaultValue;
|
||||||
|
if (colattr.IsNullable == false && colattr.DbDefautValue == null) {
|
||||||
|
var consturctorType = p.PropertyType.GenericTypeArguments.FirstOrDefault() ?? p.PropertyType;
|
||||||
|
colattr.DbDefautValue = Activator.CreateInstance(consturctorType);
|
||||||
|
}
|
||||||
|
|
||||||
|
var col = new ColumnInfo {
|
||||||
|
Table = trytb,
|
||||||
|
CsName = p.Name,
|
||||||
|
CsType = p.PropertyType,
|
||||||
|
Attribute = colattr
|
||||||
};
|
};
|
||||||
if (string.IsNullOrEmpty(colattr.DbType)) colattr.DbType = tp?.dbtypeFull ?? "varchar(255)";
|
trytb.Columns.Add(colattr.Name, col);
|
||||||
colattr.DbType = colattr.DbType.ToUpper();
|
trytb.ColumnsByCs.Add(p.Name, col);
|
||||||
|
|
||||||
if (tp != null && tp.Value.isnullable == null) colattr.IsNullable = tp.Value.dbtypeFull.Contains("NOT NULL") == false;
|
|
||||||
if (colattr.DbType?.Contains("NOT NULL") == true) colattr.IsNullable = false;
|
|
||||||
if (string.IsNullOrEmpty(colattr.Name)) colattr.Name = p.Name;
|
|
||||||
if (common.CodeFirst.IsSyncStructureToLower) colattr.Name = colattr.Name.ToLower();
|
|
||||||
|
|
||||||
if ((colattr.IsNullable == false || colattr.IsIdentity || colattr.IsPrimary) && colattr.DbType.Contains("NOT NULL") == false) {
|
|
||||||
colattr.IsNullable = false;
|
|
||||||
colattr.DbType += " NOT NULL";
|
|
||||||
}
|
}
|
||||||
if (colattr.IsNullable == true && colattr.DbType.Contains("NOT NULL")) colattr.DbType = colattr.DbType.Replace("NOT NULL", "");
|
trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsPrimary).ToArray();
|
||||||
colattr.DbType = Regex.Replace(colattr.DbType, @"\([^\)]+\)", m => {
|
if (trytb.Primarys.Any() == false) {
|
||||||
var tmpLt = Regex.Replace(m.Groups[0].Value, @"\s", "");
|
trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsIdentity).ToArray();
|
||||||
if (tmpLt.Contains("CHAR")) tmpLt = tmpLt.Replace("CHAR", " CHAR");
|
foreach (var col in trytb.Primarys)
|
||||||
if (tmpLt.Contains("BYTE")) tmpLt = tmpLt.Replace("BYTE", " BYTE");
|
col.Attribute.IsPrimary = true;
|
||||||
return tmpLt;
|
|
||||||
});
|
|
||||||
colattr.DbDefautValue = trytb.Properties[p.Name].GetValue(Activator.CreateInstance(trytb.Type));
|
|
||||||
if (colattr.DbDefautValue == null) colattr.DbDefautValue = tp?.defaultValue;
|
|
||||||
if (colattr.IsNullable == false && colattr.DbDefautValue == null) {
|
|
||||||
var consturctorType = p.PropertyType.GenericTypeArguments.FirstOrDefault() ?? p.PropertyType;
|
|
||||||
colattr.DbDefautValue = Activator.CreateInstance(consturctorType);
|
|
||||||
}
|
}
|
||||||
|
_cacheGetTableByEntity.TryAdd(entity.FullName, trytb);
|
||||||
var col = new ColumnInfo {
|
return trytb;
|
||||||
Table = trytb,
|
});
|
||||||
CsName = p.Name,
|
|
||||||
CsType = p.PropertyType,
|
|
||||||
Attribute = colattr
|
|
||||||
};
|
|
||||||
trytb.Columns.Add(colattr.Name, col);
|
|
||||||
trytb.ColumnsByCs.Add(p.Name, col);
|
|
||||||
}
|
|
||||||
trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsPrimary).ToArray();
|
|
||||||
if (trytb.Primarys.Any() == false) {
|
|
||||||
trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsIdentity).ToArray();
|
|
||||||
foreach(var col in trytb.Primarys)
|
|
||||||
col.Attribute.IsPrimary = true;
|
|
||||||
}
|
|
||||||
_cacheGetTableByEntity.TryAdd(entity.FullName, trytb);
|
|
||||||
return trytb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static T[] GetDbParamtersByObject<T>(string sql, object obj, string paramPrefix, Func<string, Type, object, T> constructorParamter) {
|
internal static T[] GetDbParamtersByObject<T>(string sql, object obj, string paramPrefix, Func<string, Type, object, T> constructorParamter) {
|
||||||
@ -166,7 +167,7 @@ namespace FreeSql.Internal {
|
|||||||
[typeof(JObject)] = true,
|
[typeof(JObject)] = true,
|
||||||
[typeof(JArray)] = true,
|
[typeof(JArray)] = true,
|
||||||
};
|
};
|
||||||
static ConcurrentDictionary<Type, Func<Type, Dictionary<string, int>, DbDataReader, int, RowInfo>> _dicExecuteArrayRowReadClassOrTuple = new ConcurrentDictionary<Type, Func<Type, Dictionary<string, int>, DbDataReader, int, RowInfo>>();
|
internal static ConcurrentDictionary<Type, Func<Type, int[], DbDataReader, int, RowInfo>> _dicExecuteArrayRowReadClassOrTuple = new ConcurrentDictionary<Type, Func<Type, int[], DbDataReader, int, RowInfo>>();
|
||||||
internal class RowInfo {
|
internal class RowInfo {
|
||||||
public object Value { get; set; }
|
public object Value { get; set; }
|
||||||
public int DataIndex { get; set; }
|
public int DataIndex { get; set; }
|
||||||
@ -179,29 +180,31 @@ namespace FreeSql.Internal {
|
|||||||
public static PropertyInfo PropertyDataIndex = typeof(RowInfo).GetProperty("DataIndex");
|
public static PropertyInfo PropertyDataIndex = typeof(RowInfo).GetProperty("DataIndex");
|
||||||
}
|
}
|
||||||
internal static MethodInfo MethodDataReaderGetValue = typeof(DbDataReader).GetMethod("GetValue");
|
internal static MethodInfo MethodDataReaderGetValue = typeof(DbDataReader).GetMethod("GetValue");
|
||||||
internal static RowInfo ExecuteArrayRowReadClassOrTuple(Type type, Dictionary<string, int> names, DbDataReader row, int dataIndex = 0) {
|
internal static RowInfo ExecuteArrayRowReadClassOrTuple(Type type, int[] indexes, DbDataReader row, int dataIndex = 0) {
|
||||||
var func = _dicExecuteArrayRowReadClassOrTuple.GetOrAdd(type, s => {
|
var func = _dicExecuteArrayRowReadClassOrTuple.GetOrAdd(type, s => {
|
||||||
var returnTarget = Expression.Label(typeof(RowInfo));
|
var returnTarget = Expression.Label(typeof(RowInfo));
|
||||||
var typeExp = Expression.Parameter(typeof(Type), "type");
|
var typeExp = Expression.Parameter(typeof(Type), "type");
|
||||||
var namesExp = Expression.Parameter(typeof(Dictionary<string, int>), "names");
|
var indexesExp = Expression.Parameter(typeof(int[]), "indexes");
|
||||||
var rowExp = Expression.Parameter(typeof(DbDataReader), "row");
|
var rowExp = Expression.Parameter(typeof(DbDataReader), "row");
|
||||||
var dataIndexExp = Expression.Parameter(typeof(int), "dataIndex");
|
var dataIndexExp = Expression.Parameter(typeof(int), "dataIndex");
|
||||||
|
|
||||||
if (type.IsArray) return Expression.Lambda<Func<Type, Dictionary<string, int>, DbDataReader, int, RowInfo>>(
|
if (type.IsArray) return Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(
|
||||||
Expression.New(RowInfo.Constructor,
|
Expression.New(RowInfo.Constructor,
|
||||||
Expression.Call(MethodGetDataReaderValue, new Expression[] { typeExp, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) /*Expression.ArrayAccess(rowExp, dataIndexExp)*/ }),
|
GetDataReaderValueBlockExpression(type, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)),
|
||||||
|
//Expression.Call(MethodGetDataReaderValue, new Expression[] { typeExp, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) }),
|
||||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
Expression.Add(dataIndexExp, Expression.Constant(1))
|
||||||
), new[] { typeExp, namesExp, rowExp, dataIndexExp }).Compile();
|
), new[] { typeExp, indexesExp, rowExp, dataIndexExp }).Compile();
|
||||||
|
|
||||||
var typeGeneric = type;
|
var typeGeneric = type;
|
||||||
if (typeGeneric.FullName.StartsWith("System.Nullable`1[")) typeGeneric = type.GenericTypeArguments.First();
|
if (typeGeneric.FullName.StartsWith("System.Nullable`1[")) typeGeneric = type.GenericTypeArguments.First();
|
||||||
if (typeGeneric.IsEnum ||
|
if (typeGeneric.IsEnum ||
|
||||||
dicExecuteArrayRowReadClassOrTuple.ContainsKey(typeGeneric))
|
dicExecuteArrayRowReadClassOrTuple.ContainsKey(typeGeneric))
|
||||||
return Expression.Lambda<Func<Type, Dictionary<string, int>, DbDataReader, int, RowInfo>>(
|
return Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(
|
||||||
Expression.New(RowInfo.Constructor,
|
Expression.New(RowInfo.Constructor,
|
||||||
Expression.Call(MethodGetDataReaderValue, new Expression[] { typeExp, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) /*Expression.ArrayAccess(rowExp, dataIndexExp)*/ }),
|
GetDataReaderValueBlockExpression(type, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)),
|
||||||
|
//Expression.Call(MethodGetDataReaderValue, new Expression[] { typeExp, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) }),
|
||||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
Expression.Add(dataIndexExp, Expression.Constant(1))
|
||||||
), new[] { typeExp, namesExp, rowExp, dataIndexExp }).Compile();
|
), new[] { typeExp, indexesExp, rowExp, dataIndexExp }).Compile();
|
||||||
|
|
||||||
if (type.Namespace == "System" && (type.FullName == "System.String" || type.IsValueType)) { //值类型,或者元组
|
if (type.Namespace == "System" && (type.FullName == "System.String" || type.IsValueType)) { //值类型,或者元组
|
||||||
bool isTuple = type.Name.StartsWith("ValueTuple`");
|
bool isTuple = type.Name.StartsWith("ValueTuple`");
|
||||||
@ -216,7 +219,8 @@ namespace FreeSql.Internal {
|
|||||||
foreach (var field in fields) {
|
foreach (var field in fields) {
|
||||||
Expression read2ExpAssign = null; //加速缓存
|
Expression read2ExpAssign = null; //加速缓存
|
||||||
if (field.FieldType.IsArray) read2ExpAssign = Expression.New(RowInfo.Constructor,
|
if (field.FieldType.IsArray) read2ExpAssign = Expression.New(RowInfo.Constructor,
|
||||||
Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(field.FieldType), Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) /*Expression.ArrayAccess(rowExp, dataIndexExp)*/ }),
|
GetDataReaderValueBlockExpression(field.FieldType, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)),
|
||||||
|
//Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(field.FieldType), Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) }),
|
||||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
Expression.Add(dataIndexExp, Expression.Constant(1))
|
||||||
);
|
);
|
||||||
else {
|
else {
|
||||||
@ -224,18 +228,19 @@ namespace FreeSql.Internal {
|
|||||||
if (fieldtypeGeneric.FullName.StartsWith("System.Nullable`1[")) fieldtypeGeneric = fieldtypeGeneric.GenericTypeArguments.First();
|
if (fieldtypeGeneric.FullName.StartsWith("System.Nullable`1[")) fieldtypeGeneric = fieldtypeGeneric.GenericTypeArguments.First();
|
||||||
if (fieldtypeGeneric.IsEnum ||
|
if (fieldtypeGeneric.IsEnum ||
|
||||||
dicExecuteArrayRowReadClassOrTuple.ContainsKey(fieldtypeGeneric)) read2ExpAssign = Expression.New(RowInfo.Constructor,
|
dicExecuteArrayRowReadClassOrTuple.ContainsKey(fieldtypeGeneric)) read2ExpAssign = Expression.New(RowInfo.Constructor,
|
||||||
Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(field.FieldType), Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) /*Expression.ArrayAccess(rowExp, dataIndexExp)*/ }),
|
GetDataReaderValueBlockExpression(field.FieldType, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)),
|
||||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
//Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(field.FieldType), Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) }),
|
||||||
|
Expression.Add(dataIndexExp, Expression.Constant(1))
|
||||||
);
|
);
|
||||||
else {
|
else {
|
||||||
read2ExpAssign = Expression.Call(MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(field.FieldType), namesExp, rowExp, dataIndexExp });
|
read2ExpAssign = Expression.Call(MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(field.FieldType), indexesExp, rowExp, dataIndexExp });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
block2Exp.AddRange(new Expression[] {
|
block2Exp.AddRange(new Expression[] {
|
||||||
//Expression.TryCatch(Expression.Block(
|
//Expression.TryCatch(Expression.Block(
|
||||||
// typeof(void),
|
// typeof(void),
|
||||||
Expression.Assign(read2Exp, read2ExpAssign),
|
Expression.Assign(read2Exp, read2ExpAssign),
|
||||||
Expression.IfThen(Expression.GreaterThan(read2ExpDataIndex, dataIndexExp),
|
Expression.IfThen(Expression.GreaterThan(read2ExpDataIndex, dataIndexExp),
|
||||||
Expression.Assign(dataIndexExp, read2ExpDataIndex)),
|
Expression.Assign(dataIndexExp, read2ExpDataIndex)),
|
||||||
Expression.IfThenElse(Expression.Equal(read2ExpValue, Expression.Constant(null)),
|
Expression.IfThenElse(Expression.Equal(read2ExpValue, Expression.Constant(null)),
|
||||||
Expression.Assign(Expression.MakeMemberAccess(ret2Exp, field), Expression.Default(field.FieldType)),
|
Expression.Assign(Expression.MakeMemberAccess(ret2Exp, field), Expression.Default(field.FieldType)),
|
||||||
@ -255,31 +260,33 @@ namespace FreeSql.Internal {
|
|||||||
Expression.Return(returnTarget, Expression.New(RowInfo.Constructor, Expression.Convert(ret2Exp, typeof(object)), dataIndexExp)),
|
Expression.Return(returnTarget, Expression.New(RowInfo.Constructor, Expression.Convert(ret2Exp, typeof(object)), dataIndexExp)),
|
||||||
Expression.Label(returnTarget, Expression.Default(typeof(RowInfo)))
|
Expression.Label(returnTarget, Expression.Default(typeof(RowInfo)))
|
||||||
});
|
});
|
||||||
return Expression.Lambda<Func<Type, Dictionary<string, int>, DbDataReader, int, RowInfo>>(
|
return Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(
|
||||||
Expression.Block(new[] { ret2Exp, read2Exp }, block2Exp), new[] { typeExp, namesExp, rowExp, dataIndexExp }).Compile();
|
Expression.Block(new[] { ret2Exp, read2Exp }, block2Exp), new[] { typeExp, indexesExp, rowExp, dataIndexExp }).Compile();
|
||||||
}
|
}
|
||||||
var rowLenExp = Expression.ArrayLength(rowExp);
|
var rowLenExp = Expression.ArrayLength(rowExp);
|
||||||
return Expression.Lambda<Func<Type, Dictionary<string, int>, DbDataReader, int, RowInfo>>(
|
return Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(
|
||||||
Expression.Block(
|
Expression.Block(
|
||||||
Expression.IfThen(
|
Expression.IfThen(
|
||||||
Expression.LessThan(dataIndexExp, rowLenExp),
|
Expression.LessThan(dataIndexExp, rowLenExp),
|
||||||
Expression.Return(returnTarget, Expression.New(RowInfo.Constructor,
|
Expression.Return(returnTarget, Expression.New(RowInfo.Constructor,
|
||||||
Expression.Call(MethodGetDataReaderValue, new Expression[] { typeExp, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) /*Expression.ArrayAccess(rowExp, dataIndexExp)*/ }),
|
GetDataReaderValueBlockExpression(type, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)),
|
||||||
|
//Expression.Call(MethodGetDataReaderValue, new Expression[] { typeExp, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) }),
|
||||||
Expression.Add(dataIndexExp, Expression.Constant(1))))
|
Expression.Add(dataIndexExp, Expression.Constant(1))))
|
||||||
),
|
),
|
||||||
Expression.Label(returnTarget, Expression.Default(typeof(RowInfo)))
|
Expression.Label(returnTarget, Expression.Default(typeof(RowInfo)))
|
||||||
), new[] { typeExp, namesExp, rowExp, dataIndexExp }).Compile();
|
), new[] { typeExp, indexesExp, rowExp, dataIndexExp }).Compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == typeof(object) && names != null) {
|
if (type == typeof(object) && indexes != null) {
|
||||||
Func<Type, Dictionary<string, int>, DbDataReader, int, RowInfo> dynamicFunc = (type2, names2, row2, dataindex2) => {
|
Func<Type, int[], DbDataReader, int, RowInfo> dynamicFunc = (type2, indexes2, row2, dataindex2) => {
|
||||||
dynamic expando = new System.Dynamic.ExpandoObject(); //动态类型字段 可读可写
|
dynamic expando = new System.Dynamic.ExpandoObject(); //动态类型字段 可读可写
|
||||||
var expandodic = (IDictionary<string, object>)expando;
|
var expandodic = (IDictionary<string, object>)expando;
|
||||||
foreach (var name in names2)
|
var fc = row2.FieldCount;
|
||||||
expandodic.Add(name.Key, row2.GetValue(name.Value));
|
for (var a = 0; a < fc; a++)
|
||||||
return new RowInfo(expando, names2.Count);
|
expandodic.Add(row2.GetName(a), row2.GetValue(a));
|
||||||
|
return new RowInfo(expando, fc);
|
||||||
};
|
};
|
||||||
return dynamicFunc;// Expression.Lambda<Func<Type, Dictionary<string, int>, DbDataReader, int, RowInfo>>(null);
|
return dynamicFunc;// Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//类注入属性
|
//类注入属性
|
||||||
@ -290,14 +297,16 @@ namespace FreeSql.Internal {
|
|||||||
var readExpValueParms = new List<ParameterExpression>();
|
var readExpValueParms = new List<ParameterExpression>();
|
||||||
var readExpsIndex = Expression.Variable(typeof(int), "readsIndex");
|
var readExpsIndex = Expression.Variable(typeof(int), "readsIndex");
|
||||||
var tryidxExp = Expression.Variable(typeof(int), "tryidx");
|
var tryidxExp = Expression.Variable(typeof(int), "tryidx");
|
||||||
|
var indexesLengthExp = Expression.Parameter(typeof(int), "indexesLength");
|
||||||
var blockExp = new List<Expression>();
|
var blockExp = new List<Expression>();
|
||||||
var ctor = type.GetConstructor(new Type[0]) ?? type.GetConstructors().First();
|
var ctor = type.GetConstructor(new Type[0]) ?? type.GetConstructors().First();
|
||||||
var ctorParms = ctor.GetParameters();
|
var ctorParms = ctor.GetParameters();
|
||||||
if (ctorParms.Length > 0) {
|
if (ctorParms.Length > 0) {
|
||||||
foreach(var ctorParm in ctorParms) {
|
foreach (var ctorParm in ctorParms) {
|
||||||
Expression readExpAssign = null; //加速缓存
|
Expression readExpAssign = null; //加速缓存
|
||||||
if (ctorParm.ParameterType.IsArray) readExpAssign = Expression.New(RowInfo.Constructor,
|
if (ctorParm.ParameterType.IsArray) readExpAssign = Expression.New(RowInfo.Constructor,
|
||||||
Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(ctorParm.ParameterType), Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) }),
|
GetDataReaderValueBlockExpression(ctorParm.ParameterType, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)),
|
||||||
|
//Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(ctorParm.ParameterType), Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) }),
|
||||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
Expression.Add(dataIndexExp, Expression.Constant(1))
|
||||||
);
|
);
|
||||||
else {
|
else {
|
||||||
@ -305,12 +314,13 @@ namespace FreeSql.Internal {
|
|||||||
if (proptypeGeneric.FullName.StartsWith("System.Nullable`1[")) proptypeGeneric = proptypeGeneric.GenericTypeArguments.First();
|
if (proptypeGeneric.FullName.StartsWith("System.Nullable`1[")) proptypeGeneric = proptypeGeneric.GenericTypeArguments.First();
|
||||||
if (proptypeGeneric.IsEnum ||
|
if (proptypeGeneric.IsEnum ||
|
||||||
dicExecuteArrayRowReadClassOrTuple.ContainsKey(proptypeGeneric)) readExpAssign = Expression.New(RowInfo.Constructor,
|
dicExecuteArrayRowReadClassOrTuple.ContainsKey(proptypeGeneric)) readExpAssign = Expression.New(RowInfo.Constructor,
|
||||||
Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(ctorParm.ParameterType), Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) }),
|
GetDataReaderValueBlockExpression(ctorParm.ParameterType, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)),
|
||||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
//Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(ctorParm.ParameterType), Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) }),
|
||||||
|
Expression.Add(dataIndexExp, Expression.Constant(1))
|
||||||
);
|
);
|
||||||
else {
|
else {
|
||||||
readExpAssign = Expression.New(RowInfo.Constructor,
|
readExpAssign = Expression.New(RowInfo.Constructor,
|
||||||
Expression.MakeMemberAccess(Expression.Call(MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(ctorParm.ParameterType), namesExp, rowExp, dataIndexExp }), RowInfo.PropertyValue),
|
Expression.MakeMemberAccess(Expression.Call(MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(ctorParm.ParameterType), indexesExp, rowExp, dataIndexExp }), RowInfo.PropertyValue),
|
||||||
Expression.Add(dataIndexExp, Expression.Constant(1)));
|
Expression.Add(dataIndexExp, Expression.Constant(1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -318,73 +328,74 @@ namespace FreeSql.Internal {
|
|||||||
readExpValueParms.Add(varctorParm);
|
readExpValueParms.Add(varctorParm);
|
||||||
blockExp.AddRange(new Expression[] {
|
blockExp.AddRange(new Expression[] {
|
||||||
Expression.Assign(tryidxExp, dataIndexExp),
|
Expression.Assign(tryidxExp, dataIndexExp),
|
||||||
//以下注释部分为【严格读取】,会损失一点性能
|
Expression.Assign(readExp, readExpAssign),
|
||||||
//Expression.IfThen(Expression.Not(Expression.And(
|
Expression.IfThen(Expression.GreaterThan(readExpDataIndex, dataIndexExp),
|
||||||
// Expression.NotEqual(namesExp, Expression.Constant(null)),
|
Expression.Assign(dataIndexExp, readExpDataIndex)),
|
||||||
// Expression.Not(Expression.Call(namesExp, namesExp.Type.GetMethod("TryGetValue"), Expression.Constant(prop.Name), tryidxExp)))),
|
Expression.IfThenElse(Expression.Equal(readExpValue, Expression.Constant(null)),
|
||||||
// Expression.Block(
|
Expression.Assign(varctorParm, Expression.Default(ctorParm.ParameterType)),
|
||||||
Expression.Assign(readExp, readExpAssign),
|
Expression.Assign(varctorParm, Expression.Convert(readExpValue, ctorParm.ParameterType)))
|
||||||
Expression.IfThen(Expression.GreaterThan(readExpDataIndex, dataIndexExp),
|
|
||||||
Expression.Assign(dataIndexExp, readExpDataIndex)),
|
|
||||||
Expression.IfThenElse(Expression.Equal(readExpValue, Expression.Constant(null)),
|
|
||||||
Expression.Assign(varctorParm, Expression.Default(ctorParm.ParameterType)),
|
|
||||||
Expression.Assign(varctorParm, Expression.Convert(readExpValue, ctorParm.ParameterType)))
|
|
||||||
// )
|
|
||||||
//)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
blockExp.Add(Expression.Assign(retExp, Expression.New(ctor, readExpValueParms)));
|
blockExp.Add(Expression.Assign(retExp, Expression.New(ctor, readExpValueParms)));
|
||||||
} else {
|
} else {
|
||||||
blockExp.Add(Expression.Assign(retExp, Expression.New(ctor)));
|
blockExp.AddRange(new Expression[] {
|
||||||
|
Expression.Assign(retExp, Expression.New(ctor)),
|
||||||
var props = type.GetProperties();
|
Expression.Assign(indexesLengthExp, Expression.Constant(0)),
|
||||||
|
Expression.IfThen(
|
||||||
|
Expression.NotEqual(indexesExp, Expression.Constant(null)),
|
||||||
|
Expression.Assign(indexesLengthExp, Expression.ArrayLength(indexesExp))
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
var props = type.GetProperties();//.ToDictionary(a => a.Name, a => a, StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
var propIndex = 0;
|
||||||
foreach (var prop in props) {
|
foreach (var prop in props) {
|
||||||
var propGetSetMethod = prop.GetSetMethod();
|
var propGetSetMethod = prop.GetSetMethod();
|
||||||
Expression readExpAssign = null; //加速缓存
|
Expression readExpAssign = null; //加速缓存
|
||||||
if (prop.PropertyType.IsArray) readExpAssign = Expression.New(RowInfo.Constructor,
|
if (prop.PropertyType.IsArray) readExpAssign = Expression.New(RowInfo.Constructor,
|
||||||
Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) /*Expression.ArrayAccess(rowExp, dataIndexExp)*/ }),
|
GetDataReaderValueBlockExpression(prop.PropertyType, Expression.Call(rowExp, MethodDataReaderGetValue, tryidxExp)),
|
||||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
//Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Call(rowExp, MethodDataReaderGetValue, tryidxExp) }),
|
||||||
|
Expression.Add(tryidxExp, Expression.Constant(1))
|
||||||
);
|
);
|
||||||
else {
|
else {
|
||||||
var proptypeGeneric = prop.PropertyType;
|
var proptypeGeneric = prop.PropertyType;
|
||||||
if (proptypeGeneric.FullName.StartsWith("System.Nullable`1[")) proptypeGeneric = proptypeGeneric.GenericTypeArguments.First();
|
if (proptypeGeneric.FullName.StartsWith("System.Nullable`1[")) proptypeGeneric = proptypeGeneric.GenericTypeArguments.First();
|
||||||
if (proptypeGeneric.IsEnum ||
|
if (proptypeGeneric.IsEnum ||
|
||||||
dicExecuteArrayRowReadClassOrTuple.ContainsKey(proptypeGeneric)) readExpAssign = Expression.New(RowInfo.Constructor,
|
dicExecuteArrayRowReadClassOrTuple.ContainsKey(proptypeGeneric)) readExpAssign = Expression.New(RowInfo.Constructor,
|
||||||
Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) /*Expression.ArrayAccess(rowExp, dataIndexExp)*/ }),
|
GetDataReaderValueBlockExpression(prop.PropertyType, Expression.Call(rowExp, MethodDataReaderGetValue, tryidxExp)),
|
||||||
Expression.Add(dataIndexExp, Expression.Constant(1))
|
//Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Call(rowExp, MethodDataReaderGetValue, tryidxExp) }),
|
||||||
|
Expression.Add(tryidxExp, Expression.Constant(1))
|
||||||
);
|
);
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
readExpAssign = Expression.Call(MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(prop.PropertyType), namesExp, rowExp, tryidxExp });
|
//readExpAssign = Expression.Call(MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(prop.PropertyType), indexesExp, rowExp, tryidxExp });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blockExp.AddRange(new Expression[] {
|
blockExp.AddRange(new Expression[] {
|
||||||
Expression.Assign(tryidxExp, dataIndexExp),
|
//以下注释部分为【严格读取】,会损失一点性能,使用 select * from xxx 与属性映射赋值
|
||||||
//以下注释部分为【严格读取】,会损失一点性能
|
Expression.IfThenElse(
|
||||||
//Expression.IfThen(Expression.Not(Expression.And(
|
Expression.LessThan(Expression.Constant(propIndex), indexesLengthExp),
|
||||||
// Expression.NotEqual(namesExp, Expression.Constant(null)),
|
Expression.Assign(tryidxExp, Expression.ArrayAccess(indexesExp, Expression.Constant(propIndex))),
|
||||||
// Expression.Not(Expression.Call(namesExp, namesExp.Type.GetMethod("TryGetValue"), Expression.Constant(prop.Name), tryidxExp)))),
|
Expression.Assign(tryidxExp, dataIndexExp)
|
||||||
// Expression.Block(
|
),
|
||||||
Expression.Assign(readExp, readExpAssign),
|
Expression.Assign(readExp, readExpAssign),
|
||||||
Expression.IfThen(Expression.GreaterThan(readExpDataIndex, dataIndexExp),
|
Expression.IfThen(Expression.GreaterThan(readExpDataIndex, dataIndexExp),
|
||||||
Expression.Assign(dataIndexExp, readExpDataIndex)),
|
Expression.Assign(dataIndexExp, readExpDataIndex)),
|
||||||
Expression.IfThenElse(Expression.Equal(readExpValue, Expression.Constant(null)),
|
Expression.IfThenElse(Expression.Equal(readExpValue, Expression.Constant(null)),
|
||||||
Expression.Call(retExp, propGetSetMethod, Expression.Default(prop.PropertyType)),
|
Expression.Call(retExp, propGetSetMethod, Expression.Default(prop.PropertyType)),
|
||||||
Expression.Call(retExp, propGetSetMethod, Expression.Convert(readExpValue, prop.PropertyType)))
|
Expression.Call(retExp, propGetSetMethod, Expression.Convert(readExpValue, prop.PropertyType)))
|
||||||
// )
|
|
||||||
//)
|
|
||||||
});
|
});
|
||||||
|
++propIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blockExp.AddRange(new Expression[] {
|
blockExp.AddRange(new Expression[] {
|
||||||
Expression.Return(returnTarget, Expression.New(RowInfo.Constructor, retExp, dataIndexExp)),
|
Expression.Return(returnTarget, Expression.New(RowInfo.Constructor, retExp, dataIndexExp)),
|
||||||
Expression.Label(returnTarget, Expression.Default(typeof(RowInfo)))
|
Expression.Label(returnTarget, Expression.Default(typeof(RowInfo)))
|
||||||
});
|
});
|
||||||
return Expression.Lambda<Func<Type, Dictionary<string, int>, DbDataReader, int, RowInfo>>(
|
return Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(
|
||||||
Expression.Block(new[] { retExp, readExp, tryidxExp, readExpsIndex }.Concat(readExpValueParms), blockExp), new[] { typeExp, namesExp, rowExp, dataIndexExp }).Compile();
|
Expression.Block(new[] { retExp, readExp, tryidxExp, readExpsIndex, indexesLengthExp }.Concat(readExpValueParms), blockExp), new[] { typeExp, indexesExp, rowExp, dataIndexExp }).Compile();
|
||||||
});
|
});
|
||||||
|
return func(type, indexes, row, dataIndex);
|
||||||
return func(type, names, row, dataIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static MethodInfo MethodExecuteArrayRowReadClassOrTuple = typeof(Utils).GetMethod("ExecuteArrayRowReadClassOrTuple", BindingFlags.Static | BindingFlags.NonPublic);
|
internal static MethodInfo MethodExecuteArrayRowReadClassOrTuple = typeof(Utils).GetMethod("ExecuteArrayRowReadClassOrTuple", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
@ -412,6 +423,7 @@ namespace FreeSql.Internal {
|
|||||||
|
|
||||||
static ConcurrentDictionary<Type, ConcurrentDictionary<Type, Func<object, object>>> _dicGetDataReaderValue = new ConcurrentDictionary<Type, ConcurrentDictionary<Type, Func<object, object>>>();
|
static ConcurrentDictionary<Type, ConcurrentDictionary<Type, Func<object, object>>> _dicGetDataReaderValue = new ConcurrentDictionary<Type, ConcurrentDictionary<Type, Func<object, object>>>();
|
||||||
static MethodInfo MethodArrayGetValue = typeof(Array).GetMethod("GetValue", new[] { typeof(int) });
|
static MethodInfo MethodArrayGetValue = typeof(Array).GetMethod("GetValue", new[] { typeof(int) });
|
||||||
|
static MethodInfo MethodArrayGetLength = typeof(Array).GetMethod("GetLength", new[] { typeof(int) });
|
||||||
static MethodInfo MethodMygisGeometryParse = typeof(MygisGeometry).GetMethod("Parse", new[] { typeof(string) });
|
static MethodInfo MethodMygisGeometryParse = typeof(MygisGeometry).GetMethod("Parse", new[] { typeof(string) });
|
||||||
static MethodInfo MethodGuidParse = typeof(Guid).GetMethod("Parse", new[] { typeof(string) });
|
static MethodInfo MethodGuidParse = typeof(Guid).GetMethod("Parse", new[] { typeof(string) });
|
||||||
static MethodInfo MethodEnumParse = typeof(Enum).GetMethod("Parse", new[] { typeof(Type), typeof(string), typeof(bool) });
|
static MethodInfo MethodEnumParse = typeof(Enum).GetMethod("Parse", new[] { typeof(Type), typeof(string), typeof(bool) });
|
||||||
@ -419,133 +431,229 @@ namespace FreeSql.Internal {
|
|||||||
static MethodInfo MethodConvertChangeType = typeof(Convert).GetMethod("ChangeType", new[] { typeof(object), typeof(Type) });
|
static MethodInfo MethodConvertChangeType = typeof(Convert).GetMethod("ChangeType", new[] { typeof(object), typeof(Type) });
|
||||||
static MethodInfo MethodTimeSpanFromSeconds = typeof(TimeSpan).GetMethod("FromSeconds");
|
static MethodInfo MethodTimeSpanFromSeconds = typeof(TimeSpan).GetMethod("FromSeconds");
|
||||||
static MethodInfo MethodDoubleParse = typeof(double).GetMethod("Parse", new[] { typeof(string) });
|
static MethodInfo MethodDoubleParse = typeof(double).GetMethod("Parse", new[] { typeof(string) });
|
||||||
internal static object GetDataReaderValue(Type type, object value) {
|
static MethodInfo MethodJTokenParse = typeof(JToken).GetMethod("Parse", new[] { typeof(string) });
|
||||||
if (value == null || value == DBNull.Value) return null;
|
static MethodInfo MethodJObjectParse = typeof(JObject).GetMethod("Parse", new[] { typeof(string) });
|
||||||
|
static MethodInfo MethodJArrayParse = typeof(JArray).GetMethod("Parse", new[] { typeof(string) });
|
||||||
var func = _dicGetDataReaderValue.GetOrAdd(type, k1 => new ConcurrentDictionary<Type, Func<object, object>>()).GetOrAdd(value.GetType(), valueType => {
|
internal static Expression GetDataReaderValueBlockExpression(Type type, Expression value) {
|
||||||
var returnTarget = Expression.Label(typeof(object));
|
var returnTarget = Expression.Label(typeof(object));
|
||||||
var parmExp = Expression.Parameter(typeof(object), "value");
|
var valueExp = Expression.Variable(typeof(object), "locvalue");
|
||||||
|
Func<Expression> funcGetExpression = () => {
|
||||||
if (type.FullName == "System.Byte[]") return Expression.Lambda<Func<object, object>>(parmExp, parmExp).Compile();
|
if (type.FullName == "System.Byte[]") return Expression.Return(returnTarget, valueExp);
|
||||||
|
|
||||||
if (type.IsArray) {
|
if (type.IsArray) {
|
||||||
var elementType = type.GetElementType();
|
var elementType = type.GetElementType();
|
||||||
if (elementType == valueType.GetElementType()) return Expression.Lambda<Func<object, object>>(parmExp, parmExp).Compile();
|
var arrNewExp = Expression.Variable(type, "arrNew");
|
||||||
|
var arrExp = Expression.Variable(typeof(Array), "arr");
|
||||||
var ret = Expression.Variable(type, "ret");
|
var arrLenExp = Expression.Variable(typeof(int), "arrLen");
|
||||||
var arr = Expression.Variable(valueType, "arr");
|
var arrXExp = Expression.Variable(typeof(int), "arrX");
|
||||||
var arrlen = Expression.Variable(typeof(int), "arrlen");
|
var arrReadValExp = Expression.Variable(typeof(object), "arrReadVal");
|
||||||
var x = Expression.Variable(typeof(int), "x");
|
|
||||||
var readval = Expression.Variable(typeof(object), "readval");
|
|
||||||
var label = Expression.Label(typeof(int));
|
var label = Expression.Label(typeof(int));
|
||||||
return Expression.Lambda<Func<object, object>>(
|
return Expression.IfThenElse(
|
||||||
|
Expression.TypeEqual(valueExp, type),
|
||||||
|
Expression.Return(returnTarget, valueExp),
|
||||||
Expression.Block(
|
Expression.Block(
|
||||||
new[] { ret, arr, arrlen, readval, x },
|
new[] { arrNewExp, arrExp, arrLenExp, arrXExp, arrReadValExp },
|
||||||
Expression.Assign(arr, Expression.TypeAs(parmExp, valueType)),
|
Expression.Assign(arrExp, Expression.TypeAs(valueExp, typeof(Array))),
|
||||||
Expression.Assign(arrlen, Expression.ArrayLength(arr)),
|
Expression.Assign(arrLenExp, Expression.Call(arrExp, MethodArrayGetLength, Expression.Constant(0))),
|
||||||
Expression.Assign(x, Expression.Constant(0)),
|
Expression.Assign(arrXExp, Expression.Constant(0)),
|
||||||
Expression.Assign(ret, Expression.NewArrayBounds(elementType, arrlen)),
|
Expression.Assign(arrNewExp, Expression.NewArrayBounds(elementType, arrLenExp)),
|
||||||
Expression.Loop(
|
Expression.Loop(
|
||||||
Expression.IfThenElse(
|
Expression.IfThenElse(
|
||||||
Expression.LessThan(x, arrlen),
|
Expression.LessThan(arrXExp, arrLenExp),
|
||||||
Expression.Block(
|
Expression.Block(
|
||||||
Expression.Assign(readval, Expression.Call(
|
Expression.Assign(arrReadValExp, GetDataReaderValueBlockExpression(elementType, Expression.Call(arrExp, MethodArrayGetValue, arrXExp))),
|
||||||
MethodGetDataReaderValue,
|
|
||||||
Expression.Constant(elementType, typeof(Type)),
|
|
||||||
Expression.Convert(Expression.ArrayAccess(arr, x), typeof(object))
|
|
||||||
)),
|
|
||||||
Expression.IfThenElse(
|
Expression.IfThenElse(
|
||||||
Expression.Equal(readval, Expression.Constant(null)),
|
Expression.Equal(arrReadValExp, Expression.Constant(null)),
|
||||||
Expression.Assign(Expression.ArrayAccess(ret, x), Expression.Default(elementType)),
|
Expression.Assign(Expression.ArrayAccess(arrNewExp, arrXExp), Expression.Default(elementType)),
|
||||||
Expression.Assign(Expression.ArrayAccess(ret, x), Expression.Convert(readval, elementType))
|
Expression.Assign(Expression.ArrayAccess(arrNewExp, arrXExp), Expression.Convert(arrReadValExp, elementType))
|
||||||
),
|
),
|
||||||
Expression.PostIncrementAssign(x)
|
Expression.PostIncrementAssign(arrXExp)
|
||||||
),
|
),
|
||||||
Expression.Break(label, x)
|
Expression.Break(label, arrXExp)
|
||||||
),
|
),
|
||||||
label
|
label
|
||||||
),
|
),
|
||||||
Expression.Return(returnTarget, ret),
|
Expression.Return(returnTarget, arrNewExp)
|
||||||
Expression.Label(returnTarget, Expression.Default(typeof(object)))
|
)
|
||||||
), parmExp).Compile();
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.FullName.StartsWith("System.Nullable`1[")) type = type.GenericTypeArguments.First();
|
if (type.FullName.StartsWith("System.Nullable`1[")) type = type.GenericTypeArguments.First();
|
||||||
if (type.IsEnum) return Expression.Lambda<Func<object, object>>(
|
if (type.IsEnum) return Expression.Return(returnTarget, Expression.Call(MethodEnumParse, Expression.Constant(type, typeof(Type)), Expression.Call(MethodToString, valueExp), Expression.Constant(true, typeof(bool))));
|
||||||
Expression.Call(
|
switch(type.FullName) {
|
||||||
MethodEnumParse,
|
case "System.Guid": return Expression.IfThenElse(
|
||||||
Expression.Constant(type, typeof(Type)),
|
Expression.TypeEqual(valueExp, type),
|
||||||
Expression.Call(MethodToString, parmExp),
|
Expression.Return(returnTarget, valueExp),
|
||||||
Expression.Constant(true, typeof(bool))
|
Expression.Return(returnTarget, Expression.Convert(Expression.Call(MethodGuidParse, Expression.Convert(valueExp, typeof(string))), typeof(object)))
|
||||||
) , parmExp).Compile();
|
);
|
||||||
|
case "MygisPoint": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisPoint)));
|
||||||
switch (type.FullName) {
|
case "MygisLineString": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisLineString)));
|
||||||
case "System.Guid":
|
case "MygisPolygon": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisPolygon)));
|
||||||
if (valueType != type) return Expression.Lambda<Func<object, object>>(
|
case "MygisMultiPoint": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisMultiPoint)));
|
||||||
Expression.Convert(Expression.Call(MethodGuidParse, Expression.Convert(parmExp, typeof(string))), typeof(object))
|
case "MygisMultiLineString": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisMultiLineString)));
|
||||||
, parmExp).Compile();
|
case "MygisMultiPolygon": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisMultiPolygon)));
|
||||||
return Expression.Lambda<Func<object, object>>(parmExp, parmExp).Compile();
|
case "Newtonsoft.Json.Linq.JToken": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJTokenParse, Expression.Convert(valueExp, typeof(string))), typeof(JToken)));
|
||||||
|
case "Newtonsoft.Json.Linq.JObject": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJObjectParse, Expression.Convert(valueExp, typeof(string))), typeof(JObject)));
|
||||||
case "MygisPoint": return Expression.Lambda<Func<object, object>>(
|
case "Newtonsoft.Json.Linq.JArray": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJArrayParse, Expression.Convert(valueExp, typeof(string))), typeof(JArray)));
|
||||||
Expression.TypeAs(
|
case "Npgsql.LegacyPostgis.PostgisGeometry": return Expression.Return(returnTarget, valueExp);
|
||||||
Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
case "System.TimeSpan": return Expression.IfThenElse(
|
||||||
typeof(MygisPoint)
|
Expression.TypeEqual(valueExp, type),
|
||||||
), parmExp).Compile();
|
Expression.Return(returnTarget, valueExp),
|
||||||
case "MygisLineString": return Expression.Lambda<Func<object, object>>(
|
Expression.Return(returnTarget, Expression.Convert(Expression.Call(MethodTimeSpanFromSeconds, Expression.Call(MethodDoubleParse, Expression.Call(MethodToString, valueExp))), typeof(object)))
|
||||||
Expression.TypeAs(
|
);
|
||||||
Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
|
||||||
typeof(MygisLineString)
|
|
||||||
), parmExp).Compile();
|
|
||||||
case "MygisPolygon": return Expression.Lambda<Func<object, object>>(
|
|
||||||
Expression.TypeAs(
|
|
||||||
Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
|
||||||
typeof(MygisPolygon)
|
|
||||||
), parmExp).Compile();
|
|
||||||
case "MygisMultiPoint": return Expression.Lambda<Func<object, object>>(
|
|
||||||
Expression.TypeAs(
|
|
||||||
Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
|
||||||
typeof(MygisMultiPoint)
|
|
||||||
), parmExp).Compile();
|
|
||||||
case "MygisMultiLineString": return Expression.Lambda<Func<object, object>>(
|
|
||||||
Expression.TypeAs(
|
|
||||||
Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
|
||||||
typeof(MygisMultiLineString)
|
|
||||||
), parmExp).Compile();
|
|
||||||
case "MygisMultiPolygon": return Expression.Lambda<Func<object, object>>(
|
|
||||||
Expression.TypeAs(
|
|
||||||
Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
|
||||||
typeof(MygisMultiPolygon)
|
|
||||||
), parmExp).Compile();
|
|
||||||
case "Newtonsoft.Json.Linq.JToken": return Expression.Lambda<Func<object, object>>(
|
|
||||||
Expression.TypeAs(
|
|
||||||
Expression.Call(typeof(JToken).GetMethod("Parse", new[] { typeof(string) }), Expression.Convert(parmExp, typeof(string))),
|
|
||||||
typeof(JToken)
|
|
||||||
), parmExp).Compile();
|
|
||||||
case "Newtonsoft.Json.Linq.JObject": return Expression.Lambda<Func<object, object>>(
|
|
||||||
Expression.TypeAs(
|
|
||||||
Expression.Call(typeof(JObject).GetMethod("Parse", new[] { typeof(string) }), Expression.Convert(parmExp, typeof(string))),
|
|
||||||
typeof(JObject)
|
|
||||||
), parmExp).Compile();
|
|
||||||
case "Newtonsoft.Json.Linq.JArray": return Expression.Lambda<Func<object, object>>(
|
|
||||||
Expression.TypeAs(
|
|
||||||
Expression.Call(typeof(JArray).GetMethod("Parse", new[] { typeof(string) }), Expression.Convert(parmExp, typeof(string))),
|
|
||||||
typeof(JArray)
|
|
||||||
), parmExp).Compile();
|
|
||||||
case "Npgsql.LegacyPostgis.PostgisGeometry": return Expression.Lambda<Func<object, object>>(parmExp, parmExp).Compile();
|
|
||||||
}
|
}
|
||||||
if (type != valueType) {
|
return Expression.IfThenElse(
|
||||||
if (type.FullName == "System.TimeSpan") return Expression.Lambda<Func<object, object>>(
|
Expression.TypeEqual(valueExp, type),
|
||||||
Expression.Convert(Expression.Call(
|
Expression.Return(returnTarget, valueExp),
|
||||||
MethodTimeSpanFromSeconds,
|
Expression.Return(returnTarget, Expression.Call(MethodConvertChangeType, valueExp, Expression.Constant(type, typeof(Type))))
|
||||||
Expression.Call(MethodDoubleParse, Expression.Call(MethodToString, parmExp))
|
);
|
||||||
), typeof(object)), parmExp).Compile();
|
};
|
||||||
return Expression.Lambda<Func<object, object>>(
|
|
||||||
Expression.Call(MethodConvertChangeType, parmExp, Expression.Constant(type, typeof(Type)))
|
return Expression.Block(
|
||||||
, parmExp).Compile();
|
new[] { valueExp },
|
||||||
}
|
Expression.Assign(valueExp, value),
|
||||||
return Expression.Lambda<Func<object, object>>(parmExp, parmExp).Compile();
|
Expression.IfThenElse(
|
||||||
|
Expression.Or(
|
||||||
|
Expression.Equal(valueExp, Expression.Constant(null)),
|
||||||
|
Expression.Equal(valueExp, Expression.Constant(DBNull.Value))
|
||||||
|
),
|
||||||
|
Expression.Return(returnTarget, Expression.Convert(Expression.Default(type), typeof(object))),
|
||||||
|
funcGetExpression()
|
||||||
|
),
|
||||||
|
Expression.Label(returnTarget, Expression.Default(typeof(object)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
internal static object GetDataReaderValue(Type type, object value) {
|
||||||
|
if (value == null || value == DBNull.Value) return null;
|
||||||
|
var func = _dicGetDataReaderValue.GetOrAdd(type, k1 => new ConcurrentDictionary<Type, Func<object, object>>()).GetOrAdd(value.GetType(), valueType => {
|
||||||
|
var parmExp = Expression.Parameter(typeof(object), "value");
|
||||||
|
var exp = GetDataReaderValueBlockExpression(type, parmExp);
|
||||||
|
return Expression.Lambda<Func<object, object>>(exp, parmExp).Compile();
|
||||||
});
|
});
|
||||||
return func(value);
|
return func(value);
|
||||||
|
|
||||||
|
//var func = _dicGetDataReaderValue.GetOrAdd(type, k1 => new ConcurrentDictionary<Type, Func<object, object>>()).GetOrAdd(value.GetType(), valueType => {
|
||||||
|
// var returnTarget = Expression.Label(typeof(object));
|
||||||
|
// var parmExp = Expression.Parameter(typeof(object), "value");
|
||||||
|
|
||||||
|
// if (type.FullName == "System.Byte[]") return Expression.Lambda<Func<object, object>>(parmExp, parmExp).Compile();
|
||||||
|
|
||||||
|
// if (type.IsArray) {
|
||||||
|
// var elementType = type.GetElementType();
|
||||||
|
// if (elementType == valueType.GetElementType()) return Expression.Lambda<Func<object, object>>(parmExp, parmExp).Compile();
|
||||||
|
|
||||||
|
// var ret = Expression.Variable(type, "ret");
|
||||||
|
// var arr = Expression.Variable(valueType, "arr");
|
||||||
|
// var arrlen = Expression.Variable(typeof(int), "arrlen");
|
||||||
|
// var x = Expression.Variable(typeof(int), "x");
|
||||||
|
// var readval = Expression.Variable(typeof(object), "readval");
|
||||||
|
// var label = Expression.Label(typeof(int));
|
||||||
|
// return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.Block(
|
||||||
|
// new[] { ret, arr, arrlen, readval, x },
|
||||||
|
// Expression.Assign(arr, Expression.TypeAs(parmExp, valueType)),
|
||||||
|
// Expression.Assign(arrlen, Expression.ArrayLength(arr)),
|
||||||
|
// Expression.Assign(x, Expression.Constant(0)),
|
||||||
|
// Expression.Assign(ret, Expression.NewArrayBounds(elementType, arrlen)),
|
||||||
|
// Expression.Loop(
|
||||||
|
// Expression.IfThenElse(
|
||||||
|
// Expression.LessThan(x, arrlen),
|
||||||
|
// Expression.Block(
|
||||||
|
// Expression.Assign(readval, Expression.Call(
|
||||||
|
// MethodGetDataReaderValue,
|
||||||
|
// Expression.Constant(elementType, typeof(Type)),
|
||||||
|
// Expression.Convert(Expression.ArrayAccess(arr, x), typeof(object))
|
||||||
|
// )),
|
||||||
|
// Expression.IfThenElse(
|
||||||
|
// Expression.Equal(readval, Expression.Constant(null)),
|
||||||
|
// Expression.Assign(Expression.ArrayAccess(ret, x), Expression.Default(elementType)),
|
||||||
|
// Expression.Assign(Expression.ArrayAccess(ret, x), Expression.Convert(readval, elementType))
|
||||||
|
// ),
|
||||||
|
// Expression.PostIncrementAssign(x)
|
||||||
|
// ),
|
||||||
|
// Expression.Break(label, x)
|
||||||
|
// ),
|
||||||
|
// label
|
||||||
|
// ),
|
||||||
|
// Expression.Return(returnTarget, ret),
|
||||||
|
// Expression.Label(returnTarget, Expression.Default(typeof(object)))
|
||||||
|
// ), parmExp).Compile();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (type.FullName.StartsWith("System.Nullable`1[")) type = type.GenericTypeArguments.First();
|
||||||
|
// if (type.IsEnum) return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.Call(
|
||||||
|
// MethodEnumParse,
|
||||||
|
// Expression.Constant(type, typeof(Type)),
|
||||||
|
// Expression.Call(MethodToString, parmExp),
|
||||||
|
// Expression.Constant(true, typeof(bool))
|
||||||
|
// ) , parmExp).Compile();
|
||||||
|
|
||||||
|
// switch (type.FullName) {
|
||||||
|
// case "System.Guid":
|
||||||
|
// if (valueType != type) return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.Convert(Expression.Call(MethodGuidParse, Expression.Convert(parmExp, typeof(string))), typeof(object))
|
||||||
|
// , parmExp).Compile();
|
||||||
|
// return Expression.Lambda<Func<object, object>>(parmExp, parmExp).Compile();
|
||||||
|
|
||||||
|
// case "MygisPoint": return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.TypeAs(
|
||||||
|
// Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
||||||
|
// typeof(MygisPoint)
|
||||||
|
// ), parmExp).Compile();
|
||||||
|
// case "MygisLineString": return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.TypeAs(
|
||||||
|
// Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
||||||
|
// typeof(MygisLineString)
|
||||||
|
// ), parmExp).Compile();
|
||||||
|
// case "MygisPolygon": return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.TypeAs(
|
||||||
|
// Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
||||||
|
// typeof(MygisPolygon)
|
||||||
|
// ), parmExp).Compile();
|
||||||
|
// case "MygisMultiPoint": return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.TypeAs(
|
||||||
|
// Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
||||||
|
// typeof(MygisMultiPoint)
|
||||||
|
// ), parmExp).Compile();
|
||||||
|
// case "MygisMultiLineString": return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.TypeAs(
|
||||||
|
// Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
||||||
|
// typeof(MygisMultiLineString)
|
||||||
|
// ), parmExp).Compile();
|
||||||
|
// case "MygisMultiPolygon": return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.TypeAs(
|
||||||
|
// Expression.Call(MethodMygisGeometryParse, Expression.Convert(parmExp, typeof(string))),
|
||||||
|
// typeof(MygisMultiPolygon)
|
||||||
|
// ), parmExp).Compile();
|
||||||
|
// case "Newtonsoft.Json.Linq.JToken": return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.TypeAs(
|
||||||
|
// Expression.Call(typeof(JToken).GetMethod("Parse", new[] { typeof(string) }), Expression.Convert(parmExp, typeof(string))),
|
||||||
|
// typeof(JToken)
|
||||||
|
// ), parmExp).Compile();
|
||||||
|
// case "Newtonsoft.Json.Linq.JObject": return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.TypeAs(
|
||||||
|
// Expression.Call(typeof(JObject).GetMethod("Parse", new[] { typeof(string) }), Expression.Convert(parmExp, typeof(string))),
|
||||||
|
// typeof(JObject)
|
||||||
|
// ), parmExp).Compile();
|
||||||
|
// case "Newtonsoft.Json.Linq.JArray": return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.TypeAs(
|
||||||
|
// Expression.Call(typeof(JArray).GetMethod("Parse", new[] { typeof(string) }), Expression.Convert(parmExp, typeof(string))),
|
||||||
|
// typeof(JArray)
|
||||||
|
// ), parmExp).Compile();
|
||||||
|
// case "Npgsql.LegacyPostgis.PostgisGeometry": return Expression.Lambda<Func<object, object>>(parmExp, parmExp).Compile();
|
||||||
|
// }
|
||||||
|
// if (type != valueType) {
|
||||||
|
// if (type.FullName == "System.TimeSpan") return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.Convert(Expression.Call(
|
||||||
|
// MethodTimeSpanFromSeconds,
|
||||||
|
// Expression.Call(MethodDoubleParse, Expression.Call(MethodToString, parmExp))
|
||||||
|
// ), typeof(object)), parmExp).Compile();
|
||||||
|
// return Expression.Lambda<Func<object, object>>(
|
||||||
|
// Expression.Call(MethodConvertChangeType, parmExp, Expression.Constant(type, typeof(Type)))
|
||||||
|
// , parmExp).Compile();
|
||||||
|
// }
|
||||||
|
// return Expression.Lambda<Func<object, object>>(parmExp, parmExp).Compile();
|
||||||
|
//});
|
||||||
|
//return func(value);
|
||||||
}
|
}
|
||||||
internal static object GetDataReaderValue22(Type type, object value) {
|
internal static object GetDataReaderValue22(Type type, object value) {
|
||||||
if (value == null || value == DBNull.Value) return null;
|
if (value == null || value == DBNull.Value) return null;
|
||||||
@ -558,7 +666,7 @@ namespace FreeSql.Internal {
|
|||||||
var ret = Array.CreateInstance(elementType, len);
|
var ret = Array.CreateInstance(elementType, len);
|
||||||
for (var a = 0; a < len; a++) {
|
for (var a = 0; a < len; a++) {
|
||||||
var item = valueArr.GetValue(a);
|
var item = valueArr.GetValue(a);
|
||||||
ret.SetValue(GetDataReaderValue(elementType, item), a);
|
ret.SetValue(GetDataReaderValue22(elementType, item), a);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace FreeSql.PostgreSQL {
|
|||||||
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
|
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
|
||||||
switch (exp.NodeType) {
|
switch (exp.NodeType) {
|
||||||
case ExpressionType.ArrayLength:
|
case ExpressionType.ArrayLength:
|
||||||
var arrOperExp = getExp((exp as UnaryExpression));
|
var arrOperExp = getExp((exp as UnaryExpression).Operand);
|
||||||
if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")")) return $"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}],1)";
|
if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")")) return $"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}],1)";
|
||||||
return $"case when {arrOperExp} is null then 0 else array_length({arrOperExp},1) end";
|
return $"case when {arrOperExp} is null then 0 else array_length({arrOperExp},1) end";
|
||||||
case ExpressionType.Call:
|
case ExpressionType.Call:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user