mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	## v0.3.20
- 修复 ToList 选择指定对象时,应附加所有字段查询返回; - 修复 Lazy 延时类与实体关系冲突 bug; - 修复 附加对象读取时,记录为空应该返回null,而不是返回非null(字段默认值)对象;
This commit is contained in:
		@@ -54,16 +54,19 @@ namespace FreeSql.Internal {
 | 
			
		||||
					field.Append(", ").Append(parent.DbField);
 | 
			
		||||
					if (index >= 0) field.Append(" as").Append(++index);
 | 
			
		||||
					return false;
 | 
			
		||||
				case ExpressionType.Parameter:
 | 
			
		||||
				case ExpressionType.MemberAccess:
 | 
			
		||||
					if (_common.GetTableByEntity(exp.Type) != null) { //加载表所有字段
 | 
			
		||||
						var map = new List<SelectColumnInfo>();
 | 
			
		||||
						ExpressionSelectColumn_MemberAccess(_tables, map, SelectTableInfoType.From, exp, true, getSelectGroupingMapString);
 | 
			
		||||
						parent.Consturctor = map.First().Table.Table.Type.GetConstructor(new Type[0]);
 | 
			
		||||
						var tb = parent.Table = map.First().Table.Table;
 | 
			
		||||
						parent.Consturctor = tb.Type.GetConstructor(new Type[0]);
 | 
			
		||||
						parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties;
 | 
			
		||||
						for (var idx = 0; idx < map.Count; idx++) {
 | 
			
		||||
							var child = new ReadAnonymousTypeInfo {
 | 
			
		||||
								Property = map.First().Table.Table.Type.GetProperty(map[idx].Column.CsName, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance),
 | 
			
		||||
								CsName = map[idx].Column.CsName, DbField = $"{map[idx].Table.Alias}.{_common.QuoteSqlName(map[idx].Column.Attribute.Name)}" };
 | 
			
		||||
								Property = tb.Properties.TryGetValue(map[idx].Column.CsName, out var tryprop) ? tryprop : tb.Type.GetProperty(map[idx].Column.CsName, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance),
 | 
			
		||||
								CsName = map[idx].Column.CsName, DbField = $"{map[idx].Table.Alias}.{_common.QuoteSqlName(map[idx].Column.Attribute.Name)}"
 | 
			
		||||
							};
 | 
			
		||||
							field.Append(", ").Append(_common.QuoteReadColumn(map[idx].Column.CsType, child.DbField));
 | 
			
		||||
							if (index >= 0) field.Append(" as").Append(++index);
 | 
			
		||||
							parent.Childs.Add(child);
 | 
			
		||||
@@ -82,7 +85,8 @@ namespace FreeSql.Internal {
 | 
			
		||||
					for (var a = 0; a < newExp.Members.Count; a++) {
 | 
			
		||||
						var child = new ReadAnonymousTypeInfo {
 | 
			
		||||
							Property = newExp.Type.GetProperty(newExp.Members[a].Name, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance),
 | 
			
		||||
							CsName = newExp.Members[a].Name, CsType = newExp.Arguments[a].Type };
 | 
			
		||||
							CsName = newExp.Members[a].Name, CsType = newExp.Arguments[a].Type
 | 
			
		||||
						};
 | 
			
		||||
						parent.Childs.Add(child);
 | 
			
		||||
						ReadAnonymousField(_tables, field, child, ref index, newExp.Arguments[a], getSelectGroupingMapString);
 | 
			
		||||
					}
 | 
			
		||||
@@ -93,22 +97,36 @@ namespace FreeSql.Internal {
 | 
			
		||||
			if (index >= 0) field.Append(" as").Append(++index);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		internal object ReadAnonymous(ReadAnonymousTypeInfo parent, DbDataReader dr, ref int index) {
 | 
			
		||||
			if (parent.Childs.Any() == false) return dr.GetValue(++index);
 | 
			
		||||
		internal object ReadAnonymous(ReadAnonymousTypeInfo parent, DbDataReader dr, ref int index, bool notRead) {
 | 
			
		||||
			if (parent.Childs.Any() == false) {
 | 
			
		||||
				if (notRead) {
 | 
			
		||||
					++index;
 | 
			
		||||
					return null;
 | 
			
		||||
				}
 | 
			
		||||
				return dr.GetValue(++index);
 | 
			
		||||
			}
 | 
			
		||||
			switch (parent.ConsturctorType) {
 | 
			
		||||
				case ReadAnonymousTypeInfoConsturctorType.Arguments:
 | 
			
		||||
					var args = new object[parent.Childs.Count];
 | 
			
		||||
					for (var a = 0; a < parent.Childs.Count; a++) {
 | 
			
		||||
						args[a] = Utils.GetDataReaderValue(parent.Childs[a].CsType, ReadAnonymous(parent.Childs[a], dr, ref index));
 | 
			
		||||
						var objval = ReadAnonymous(parent.Childs[a], dr, ref index, notRead);
 | 
			
		||||
						if (notRead == false)
 | 
			
		||||
							args[a] = Utils.GetDataReaderValue(parent.Childs[a].CsType, objval);
 | 
			
		||||
					}
 | 
			
		||||
					return parent.Consturctor.Invoke(args);
 | 
			
		||||
				case ReadAnonymousTypeInfoConsturctorType.Properties:
 | 
			
		||||
					var ret = parent.Consturctor.Invoke(null);
 | 
			
		||||
					var isnull = notRead;
 | 
			
		||||
					for (var b = 0; b < parent.Childs.Count; b++) {
 | 
			
		||||
						var prop = parent.Childs[b].Property;
 | 
			
		||||
						prop.SetValue(ret, Utils.GetDataReaderValue(prop.PropertyType, ReadAnonymous(parent.Childs[b], dr, ref index)), null);
 | 
			
		||||
						var objval = ReadAnonymous(parent.Childs[b], dr, ref index, notRead);
 | 
			
		||||
						var safeval = Utils.GetDataReaderValue(prop.PropertyType, objval);
 | 
			
		||||
						if (isnull == false && safeval == null && parent.Table.ColumnsByCs.TryGetValue(parent.Childs[b].CsName, out var trycol) && trycol.Attribute.IsPrimary)
 | 
			
		||||
							isnull = true;
 | 
			
		||||
						if (isnull == false)
 | 
			
		||||
							prop.SetValue(ret, safeval, null);
 | 
			
		||||
					}
 | 
			
		||||
					return ret;
 | 
			
		||||
					return isnull ? null : ret;
 | 
			
		||||
			}
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
@@ -445,24 +463,26 @@ namespace FreeSql.Internal {
 | 
			
		||||
					var other3Exp = ExpressionLambdaToSqlOther(exp3, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
			
		||||
					if (string.IsNullOrEmpty(other3Exp) == false) return other3Exp;
 | 
			
		||||
					throw new Exception($"未实现函数表达式 {exp3} 解析");
 | 
			
		||||
				case ExpressionType.Parameter:
 | 
			
		||||
				case ExpressionType.MemberAccess:
 | 
			
		||||
					var exp4 = exp as MemberExpression;
 | 
			
		||||
					if (exp4.Expression != null && exp4.Expression.Type.IsArray == false && exp4.Expression.Type.IsNullableType()) return ExpressionLambdaToSql(exp4.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
			
		||||
					var extRet = "";
 | 
			
		||||
					var memberType = exp4.Expression?.Type ?? exp4.Type;
 | 
			
		||||
					switch (memberType.FullName) {
 | 
			
		||||
						case "System.String": extRet = ExpressionLambdaToSqlMemberAccessString(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break;
 | 
			
		||||
						case "System.DateTime": extRet = ExpressionLambdaToSqlMemberAccessDateTime(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break;
 | 
			
		||||
						case "System.TimeSpan": extRet = ExpressionLambdaToSqlMemberAccessTimeSpan(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break;
 | 
			
		||||
					if (exp4 != null) {
 | 
			
		||||
						if (exp4.Expression != null && exp4.Expression.Type.IsArray == false && exp4.Expression.Type.IsNullableType()) return ExpressionLambdaToSql(exp4.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
			
		||||
						var extRet = "";
 | 
			
		||||
						var memberType = exp4.Expression?.Type ?? exp4.Type;
 | 
			
		||||
						switch (memberType.FullName) {
 | 
			
		||||
							case "System.String": extRet = ExpressionLambdaToSqlMemberAccessString(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break;
 | 
			
		||||
							case "System.DateTime": extRet = ExpressionLambdaToSqlMemberAccessDateTime(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break;
 | 
			
		||||
							case "System.TimeSpan": extRet = ExpressionLambdaToSqlMemberAccessTimeSpan(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break;
 | 
			
		||||
						}
 | 
			
		||||
						if (string.IsNullOrEmpty(extRet) == false) return extRet;
 | 
			
		||||
						var other4Exp = ExpressionLambdaToSqlOther(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
			
		||||
						if (string.IsNullOrEmpty(other4Exp) == false) return other4Exp;
 | 
			
		||||
					}
 | 
			
		||||
					if (string.IsNullOrEmpty(extRet) == false) return extRet;
 | 
			
		||||
					var other4Exp = ExpressionLambdaToSqlOther(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
			
		||||
					if (string.IsNullOrEmpty(other4Exp) == false) return other4Exp;
 | 
			
		||||
 | 
			
		||||
					var expStack = new Stack<Expression>();
 | 
			
		||||
					expStack.Push(exp);
 | 
			
		||||
					MethodCallExpression callExp = null;
 | 
			
		||||
					var exp2 = exp4.Expression;
 | 
			
		||||
					var exp2 = exp4?.Expression;
 | 
			
		||||
					while (true) {
 | 
			
		||||
						switch(exp2?.NodeType) {
 | 
			
		||||
							case ExpressionType.Constant:
 | 
			
		||||
@@ -508,7 +528,11 @@ namespace FreeSql.Internal {
 | 
			
		||||
					}
 | 
			
		||||
					Func<TableInfo, string, bool, ParameterExpression, MemberExpression, SelectTableInfo> getOrAddTable = (tbtmp, alias, isa, parmExp, mp) => {
 | 
			
		||||
						var finds = new SelectTableInfo[0];
 | 
			
		||||
						if (isa && parmExp != null)
 | 
			
		||||
						if (_selectColumnMap != null) {
 | 
			
		||||
							finds = _tables.Where(a => a.Table.Type == tbtmp.Type).ToArray();
 | 
			
		||||
							if (finds.Any()) finds = new[] { finds.First() };
 | 
			
		||||
						}
 | 
			
		||||
						if (finds.Length != 1 && isa && parmExp != null)
 | 
			
		||||
							finds = _tables.Where(a => a.Parameter == parmExp).ToArray();
 | 
			
		||||
						if (finds.Length != 1) {
 | 
			
		||||
							var navdot = string.IsNullOrEmpty(alias) ? new SelectTableInfo[0] : _tables.Where(a2 => a2.Parameter != null && alias.StartsWith($"{a2.Alias}__")).ToArray();
 | 
			
		||||
@@ -605,6 +629,13 @@ namespace FreeSql.Internal {
 | 
			
		||||
									alias2 = find2.Alias;
 | 
			
		||||
									tb2 = tb2tmp;
 | 
			
		||||
								}
 | 
			
		||||
								if (exp2.NodeType == ExpressionType.Parameter && expStack.Any() == false) { //附加选择的参数所有列
 | 
			
		||||
									if (_selectColumnMap != null) {
 | 
			
		||||
										foreach (var tb2c in tb2.Columns.Values)
 | 
			
		||||
											_selectColumnMap.Add(new SelectColumnInfo { Table = find2, Column = tb2c });
 | 
			
		||||
										if (tb2.Columns.Any()) return "";
 | 
			
		||||
									}
 | 
			
		||||
								}
 | 
			
		||||
								if (mp2 == null || expStack.Any()) continue;
 | 
			
		||||
								if (tb2.ColumnsByCs.ContainsKey(mp2.Member.Name) == false) { //如果选的是对象,附加所有列
 | 
			
		||||
									if (_selectColumnMap != null) {
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
		public DataType DataType { get; }
 | 
			
		||||
		protected ICache _cache { get; set; }
 | 
			
		||||
		protected ILogger _log { get; set; }
 | 
			
		||||
		protected CommonUtils _util { get; set; }
 | 
			
		||||
		protected int slaveUnavailables = 0;
 | 
			
		||||
		private object slaveLock = new object();
 | 
			
		||||
		private Random slaveRandom = new Random();
 | 
			
		||||
@@ -89,7 +90,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
						dic.Add(dr.GetName(a), a);
 | 
			
		||||
					indexes = props.Select(a => dic.TryGetValue(a.Name, out var tryint) ? tryint : -1).ToArray();
 | 
			
		||||
				}
 | 
			
		||||
				ret.Add((T)Utils.ExecuteArrayRowReadClassOrTuple(type, indexes, dr, 0).Value);
 | 
			
		||||
				ret.Add((T)Utils.ExecuteArrayRowReadClassOrTuple(type, indexes, dr, 0, _util).Value);
 | 
			
		||||
			}, cmdType, cmdText, cmdParms);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
						dic.Add(dr.GetName(a), a);
 | 
			
		||||
					indexes = props.Select(a => dic.TryGetValue(a.Name, out var tryint) ? tryint : -1).ToArray();
 | 
			
		||||
				}
 | 
			
		||||
				ret.Add((T)Utils.ExecuteArrayRowReadClassOrTuple(type, indexes, dr, 0).Value);
 | 
			
		||||
				ret.Add((T)Utils.ExecuteArrayRowReadClassOrTuple(type, indexes, dr, 0, _util).Value);
 | 
			
		||||
				return Task.CompletedTask;
 | 
			
		||||
			}, cmdType, cmdText, cmdParms);
 | 
			
		||||
			return ret;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
 | 
			
		||||
using System.Collections.ObjectModel;
 | 
			
		||||
using System.Data;
 | 
			
		||||
using System.Data.Common;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
@@ -211,7 +212,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
				List<TTuple> ret = new List<TTuple>();
 | 
			
		||||
				Type type = typeof(TTuple);
 | 
			
		||||
				_orm.Ado.ExecuteReader(_transaction, dr => {
 | 
			
		||||
					var read = Utils.ExecuteArrayRowReadClassOrTuple(type, null, dr);
 | 
			
		||||
					var read = Utils.ExecuteArrayRowReadClassOrTuple(type, null, dr, 0, _commonUtils);
 | 
			
		||||
					ret.Add((TTuple)read.Value);
 | 
			
		||||
				}, CommandType.Text, sql, _params.ToArray());
 | 
			
		||||
				return ret;
 | 
			
		||||
@@ -225,7 +226,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
				List<TTuple> ret = new List<TTuple>();
 | 
			
		||||
				Type type = typeof(TTuple);
 | 
			
		||||
				await _orm.Ado.ExecuteReaderAsync(_transaction, dr => {
 | 
			
		||||
					var read = Utils.ExecuteArrayRowReadClassOrTuple(type, null, dr);
 | 
			
		||||
					var read = Utils.ExecuteArrayRowReadClassOrTuple(type, null, dr, 0, _commonUtils);
 | 
			
		||||
					ret.Add((TTuple)read.Value);
 | 
			
		||||
					return Task.CompletedTask;
 | 
			
		||||
				}, CommandType.Text, sql, _params.ToArray());
 | 
			
		||||
@@ -280,7 +281,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
				Type type = typeof(TReturn);
 | 
			
		||||
				_orm.Ado.ExecuteReader(_transaction, dr => {
 | 
			
		||||
					var index = -1;
 | 
			
		||||
					ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index));
 | 
			
		||||
					ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index, false));
 | 
			
		||||
				}, CommandType.Text, sql, _params.ToArray());
 | 
			
		||||
				return ret;
 | 
			
		||||
			});
 | 
			
		||||
@@ -294,7 +295,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
				Type type = typeof(TReturn);
 | 
			
		||||
				await _orm.Ado.ExecuteReaderAsync(_transaction, dr => {
 | 
			
		||||
					var index = -1;
 | 
			
		||||
					ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index));
 | 
			
		||||
					ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index, false));
 | 
			
		||||
					return Task.CompletedTask;
 | 
			
		||||
				}, CommandType.Text, sql, _params.ToArray());
 | 
			
		||||
				return ret;
 | 
			
		||||
@@ -387,15 +388,16 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
								Expression.Add(dataIndexExp, Expression.Constant(1))
 | 
			
		||||
						);
 | 
			
		||||
						else {
 | 
			
		||||
							readExpAssign = Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp });
 | 
			
		||||
							readExpAssign = Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp, Expression.Constant(_commonUtils) });
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					blockExp.AddRange(new Expression[] {
 | 
			
		||||
						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(typeof(Trace).GetMethod("WriteLine", new Type[]{typeof(string)}), Expression.Call(typeof(string).GetMethod("Concat", new Type[]{typeof(object) }), readExpValue)),
 | 
			
		||||
						Expression.IfThen(Expression.NotEqual(readExpValue, Expression.Constant(null)),
 | 
			
		||||
							//Expression.Call(retExp, propGetSetMethod, Expression.Default(prop.PropertyType)),
 | 
			
		||||
							Expression.Call(retExp, propGetSetMethod, Expression.Convert(readExpValue, prop.PropertyType)))
 | 
			
		||||
					});
 | 
			
		||||
				}
 | 
			
		||||
@@ -403,7 +405,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
					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(readExp, Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(type), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp, Expression.Constant(_commonUtils) })),
 | 
			
		||||
						Expression.Assign(retExp, Expression.Convert(readExpValue, type))
 | 
			
		||||
					});
 | 
			
		||||
				}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ namespace FreeSql.Internal.Model {
 | 
			
		||||
		public ConstructorInfo Consturctor { get; set; }
 | 
			
		||||
		public ReadAnonymousTypeInfoConsturctorType ConsturctorType { get; set; }
 | 
			
		||||
		public List<ReadAnonymousTypeInfo> Childs = new List<ReadAnonymousTypeInfo>();
 | 
			
		||||
		public TableInfo Table { get; set; }
 | 
			
		||||
	}
 | 
			
		||||
	enum ReadAnonymousTypeInfoConsturctorType { Arguments, Properties }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
		internal static void RemoveTableByEntity(Type entity, CommonUtils common) {
 | 
			
		||||
			if (entity.FullName.StartsWith("<>f__AnonymousType")) return;
 | 
			
		||||
			var tbc = _cacheGetTableByEntity.GetOrAdd(common._orm.Ado.DataType, k1 => new ConcurrentDictionary<Type, TableInfo>()); //区分数据库类型缓存
 | 
			
		||||
			tbc.TryRemove(entity, out var trytb);
 | 
			
		||||
			if (tbc.TryRemove(entity, out var trytb) && trytb?.TypeLazy != null) tbc.TryRemove(trytb.TypeLazy, out var trylz);
 | 
			
		||||
		}
 | 
			
		||||
		internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) {
 | 
			
		||||
			if (entity.FullName.StartsWith("<>f__AnonymousType")) return null;
 | 
			
		||||
@@ -573,6 +573,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
				var type = assembly.DefinedTypes.Where(a => a.FullName.EndsWith(trytbTypeLazyName)).FirstOrDefault();
 | 
			
		||||
				trytb.TypeLazy = type;
 | 
			
		||||
				trytb.TypeLazySetOrm = type.GetProperty("__fsql_orm__", BindingFlags.Instance | BindingFlags.NonPublic).GetSetMethod(true);
 | 
			
		||||
				tbc.AddOrUpdate(type, trytb, (oldkey, oldval) => trytb);
 | 
			
		||||
			}
 | 
			
		||||
			#endregion
 | 
			
		||||
 | 
			
		||||
@@ -648,7 +649,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			//[typeof(JObject)] = true,
 | 
			
		||||
			//[typeof(JArray)] = true,
 | 
			
		||||
		};
 | 
			
		||||
		internal static ConcurrentDictionary<Type, Func<Type, int[], DbDataReader, int, RowInfo>> _dicExecuteArrayRowReadClassOrTuple = new ConcurrentDictionary<Type, Func<Type, int[], DbDataReader, int, RowInfo>>();
 | 
			
		||||
		internal static ConcurrentDictionary<Type, Func<Type, int[], DbDataReader, int, CommonUtils, RowInfo>> _dicExecuteArrayRowReadClassOrTuple = new ConcurrentDictionary<Type, Func<Type, int[], DbDataReader, int, CommonUtils, RowInfo>>();
 | 
			
		||||
		internal class RowInfo {
 | 
			
		||||
			public object Value { get; set; }
 | 
			
		||||
			public int DataIndex { get; set; }
 | 
			
		||||
@@ -661,31 +662,32 @@ namespace FreeSql.Internal {
 | 
			
		||||
			public static PropertyInfo PropertyDataIndex = typeof(RowInfo).GetProperty("DataIndex");
 | 
			
		||||
		}
 | 
			
		||||
		internal static MethodInfo MethodDataReaderGetValue = typeof(DbDataReader).GetMethod("GetValue");
 | 
			
		||||
		internal static RowInfo ExecuteArrayRowReadClassOrTuple(Type type, int[] indexes, DbDataReader row, int dataIndex = 0) {
 | 
			
		||||
		internal static RowInfo ExecuteArrayRowReadClassOrTuple(Type type, int[] indexes, DbDataReader row, int dataIndex, CommonUtils _commonUtils) {
 | 
			
		||||
			var func = _dicExecuteArrayRowReadClassOrTuple.GetOrAdd(type, s => {
 | 
			
		||||
				var returnTarget = Expression.Label(typeof(RowInfo));
 | 
			
		||||
				var typeExp = Expression.Parameter(typeof(Type), "type");
 | 
			
		||||
				var indexesExp = Expression.Parameter(typeof(int[]), "indexes");
 | 
			
		||||
				var rowExp = Expression.Parameter(typeof(DbDataReader), "row");
 | 
			
		||||
				var dataIndexExp = Expression.Parameter(typeof(int), "dataIndex");
 | 
			
		||||
				var commonUtilExp = Expression.Parameter(typeof(CommonUtils), "commonUtil");
 | 
			
		||||
 | 
			
		||||
				if (type.IsArray) return Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(
 | 
			
		||||
				if (type.IsArray) return Expression.Lambda<Func<Type, int[], DbDataReader, int, CommonUtils, RowInfo>>(
 | 
			
		||||
					Expression.New(RowInfo.Constructor,
 | 
			
		||||
						GetDataReaderValueBlockExpression(type, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)),
 | 
			
		||||
						//Expression.Call(MethodGetDataReaderValue, new Expression[] { typeExp, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) }),
 | 
			
		||||
						Expression.Add(dataIndexExp, Expression.Constant(1))
 | 
			
		||||
					), new[] { typeExp, indexesExp, rowExp, dataIndexExp }).Compile();
 | 
			
		||||
					), new[] { typeExp, indexesExp, rowExp, dataIndexExp, commonUtilExp }).Compile();
 | 
			
		||||
 | 
			
		||||
				var typeGeneric = type;
 | 
			
		||||
				if (typeGeneric.IsNullableType()) typeGeneric = type.GenericTypeArguments.First();
 | 
			
		||||
				if (typeGeneric.IsEnum ||
 | 
			
		||||
					dicExecuteArrayRowReadClassOrTuple.ContainsKey(typeGeneric))
 | 
			
		||||
					return Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(
 | 
			
		||||
					return Expression.Lambda<Func<Type, int[], DbDataReader, int, CommonUtils, RowInfo>>(
 | 
			
		||||
					Expression.New(RowInfo.Constructor,
 | 
			
		||||
						GetDataReaderValueBlockExpression(type, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)),
 | 
			
		||||
						//Expression.Call(MethodGetDataReaderValue, new Expression[] { typeExp, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp) }),
 | 
			
		||||
						Expression.Add(dataIndexExp, Expression.Constant(1))
 | 
			
		||||
					), new[] { typeExp, indexesExp, rowExp, dataIndexExp }).Compile();
 | 
			
		||||
					), new[] { typeExp, indexesExp, rowExp, dataIndexExp, commonUtilExp }).Compile();
 | 
			
		||||
 | 
			
		||||
				if (type.Namespace == "System" && (type.FullName == "System.String" || type.IsValueType)) { //值类型,或者元组
 | 
			
		||||
					bool isTuple = type.Name.StartsWith("ValueTuple`");
 | 
			
		||||
@@ -714,7 +716,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
										Expression.Add(dataIndexExp, Expression.Constant(1))
 | 
			
		||||
								);
 | 
			
		||||
								else {
 | 
			
		||||
									read2ExpAssign = Expression.Call(MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(field.FieldType), indexesExp, rowExp, dataIndexExp });
 | 
			
		||||
									read2ExpAssign = Expression.Call(MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(field.FieldType), indexesExp, rowExp, dataIndexExp, commonUtilExp });
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
							block2Exp.AddRange(new Expression[] {
 | 
			
		||||
@@ -741,11 +743,11 @@ namespace FreeSql.Internal {
 | 
			
		||||
							Expression.Return(returnTarget, Expression.New(RowInfo.Constructor, Expression.Convert(ret2Exp, typeof(object)), dataIndexExp)),
 | 
			
		||||
							Expression.Label(returnTarget, Expression.Default(typeof(RowInfo)))
 | 
			
		||||
						});
 | 
			
		||||
						return Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(
 | 
			
		||||
							Expression.Block(new[] { ret2Exp, read2Exp }, block2Exp), new[] { typeExp, indexesExp, rowExp, dataIndexExp }).Compile();
 | 
			
		||||
						return Expression.Lambda<Func<Type, int[], DbDataReader, int, CommonUtils, RowInfo>>(
 | 
			
		||||
							Expression.Block(new[] { ret2Exp, read2Exp }, block2Exp), new[] { typeExp, indexesExp, rowExp, dataIndexExp, commonUtilExp }).Compile();
 | 
			
		||||
					}
 | 
			
		||||
					var rowLenExp = Expression.ArrayLength(rowExp);
 | 
			
		||||
					return Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(
 | 
			
		||||
					return Expression.Lambda<Func<Type, int[], DbDataReader, int, CommonUtils, RowInfo>>(
 | 
			
		||||
						Expression.Block(
 | 
			
		||||
							Expression.IfThen(
 | 
			
		||||
								Expression.LessThan(dataIndexExp, rowLenExp),
 | 
			
		||||
@@ -755,11 +757,11 @@ namespace FreeSql.Internal {
 | 
			
		||||
										Expression.Add(dataIndexExp, Expression.Constant(1))))
 | 
			
		||||
							),
 | 
			
		||||
							Expression.Label(returnTarget, Expression.Default(typeof(RowInfo)))
 | 
			
		||||
						), new[] { typeExp, indexesExp, rowExp, dataIndexExp }).Compile();
 | 
			
		||||
						), new[] { typeExp, indexesExp, rowExp, dataIndexExp, commonUtilExp }).Compile();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (type == typeof(object) && indexes != null) {
 | 
			
		||||
					Func<Type, int[], DbDataReader, int, RowInfo> dynamicFunc = (type2, indexes2, row2, dataindex2) => {
 | 
			
		||||
					Func<Type, int[], DbDataReader, int, CommonUtils, RowInfo> dynamicFunc = (type2, indexes2, row2, dataindex2, commonUtils2) => {
 | 
			
		||||
						dynamic expando = new System.Dynamic.ExpandoObject(); //动态类型字段 可读可写
 | 
			
		||||
						var expandodic = (IDictionary<string, object>)expando;
 | 
			
		||||
						var fc = row2.FieldCount;
 | 
			
		||||
@@ -771,6 +773,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				//类注入属性
 | 
			
		||||
				var typetb = GetTableByEntity(type, _commonUtils);
 | 
			
		||||
				var retExp = Expression.Variable(type, "ret");
 | 
			
		||||
				var readExp = Expression.Variable(typeof(RowInfo), "read");
 | 
			
		||||
				var readExpValue = Expression.MakeMemberAccess(readExp, RowInfo.PropertyValue);
 | 
			
		||||
@@ -778,12 +781,18 @@ namespace FreeSql.Internal {
 | 
			
		||||
				var readExpValueParms = new List<ParameterExpression>();
 | 
			
		||||
				var readExpsIndex = Expression.Variable(typeof(int), "readsIndex");
 | 
			
		||||
				var tryidxExp = Expression.Variable(typeof(int), "tryidx");
 | 
			
		||||
				var indexesLengthExp = Expression.Parameter(typeof(int), "indexesLength");
 | 
			
		||||
				var readpknullExp = Expression.Variable(typeof(bool), "isnull2");
 | 
			
		||||
				var readpkvalExp = Expression.Variable(typeof(object), "isnull3val");
 | 
			
		||||
				var indexesLengthExp = Expression.Variable(typeof(int), "indexesLength");
 | 
			
		||||
				var blockExp = new List<Expression>();
 | 
			
		||||
				var ctor = type.GetConstructor(new Type[0]) ?? type.GetConstructors().First();
 | 
			
		||||
				var ctorParms = ctor.GetParameters();
 | 
			
		||||
				if (ctorParms.Length > 0) {
 | 
			
		||||
					blockExp.AddRange(new Expression[] {
 | 
			
		||||
						Expression.Assign(readpknullExp, Expression.Constant(false))
 | 
			
		||||
					});
 | 
			
		||||
					foreach (var ctorParm in ctorParms) {
 | 
			
		||||
						var ispkExp = new List<Expression>();
 | 
			
		||||
						Expression readExpAssign = null; //加速缓存
 | 
			
		||||
						if (ctorParm.ParameterType.IsArray) readExpAssign = Expression.New(RowInfo.Constructor,
 | 
			
		||||
							GetDataReaderValueBlockExpression(ctorParm.ParameterType, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)),
 | 
			
		||||
@@ -794,30 +803,64 @@ namespace FreeSql.Internal {
 | 
			
		||||
							var proptypeGeneric = ctorParm.ParameterType;
 | 
			
		||||
							if (proptypeGeneric.IsNullableType()) proptypeGeneric = proptypeGeneric.GenericTypeArguments.First();
 | 
			
		||||
							if (proptypeGeneric.IsEnum ||
 | 
			
		||||
								dicExecuteArrayRowReadClassOrTuple.ContainsKey(proptypeGeneric)) readExpAssign = Expression.New(RowInfo.Constructor,
 | 
			
		||||
									GetDataReaderValueBlockExpression(ctorParm.ParameterType, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)),
 | 
			
		||||
								dicExecuteArrayRowReadClassOrTuple.ContainsKey(proptypeGeneric)) {
 | 
			
		||||
 | 
			
		||||
								//判断主键为空,则整个对象不读取
 | 
			
		||||
								blockExp.Add(Expression.Assign(readpkvalExp, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)));
 | 
			
		||||
								if (typetb.ColumnsByCs.TryGetValue(ctorParm.Name, out var trycol) && trycol.Attribute.IsPrimary) {
 | 
			
		||||
									ispkExp.Add(
 | 
			
		||||
										Expression.IfThen(
 | 
			
		||||
											Expression.And(
 | 
			
		||||
												Expression.IsFalse(readpknullExp),
 | 
			
		||||
												Expression.Or(
 | 
			
		||||
													Expression.Equal(readpkvalExp, Expression.Constant(DBNull.Value)),
 | 
			
		||||
													Expression.Equal(readpkvalExp, Expression.Constant(null))
 | 
			
		||||
												)
 | 
			
		||||
											),
 | 
			
		||||
											Expression.Assign(readpknullExp, Expression.Constant(true))
 | 
			
		||||
										)
 | 
			
		||||
									);
 | 
			
		||||
								}
 | 
			
		||||
 | 
			
		||||
								readExpAssign = Expression.New(RowInfo.Constructor,
 | 
			
		||||
									GetDataReaderValueBlockExpression(ctorParm.ParameterType, readpkvalExp),
 | 
			
		||||
									//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,
 | 
			
		||||
									Expression.MakeMemberAccess(Expression.Call(MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(ctorParm.ParameterType), indexesExp, rowExp, dataIndexExp }), RowInfo.PropertyValue),
 | 
			
		||||
									Expression.MakeMemberAccess(Expression.Call(MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(ctorParm.ParameterType), indexesExp, rowExp, dataIndexExp, commonUtilExp }), RowInfo.PropertyValue),
 | 
			
		||||
									Expression.Add(dataIndexExp, Expression.Constant(1)));
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						var varctorParm = Expression.Variable(ctorParm.ParameterType, $"ctorParm{ctorParm.Name}");
 | 
			
		||||
						readExpValueParms.Add(varctorParm);
 | 
			
		||||
 | 
			
		||||
						ispkExp.Add(
 | 
			
		||||
							Expression.IfThen(
 | 
			
		||||
								Expression.IsFalse(readpknullExp),
 | 
			
		||||
								Expression.IfThenElse(
 | 
			
		||||
									Expression.Equal(readExpValue, Expression.Constant(null)),
 | 
			
		||||
									Expression.Assign(varctorParm, Expression.Default(ctorParm.ParameterType)),
 | 
			
		||||
									Expression.Assign(varctorParm, Expression.Convert(readExpValue, ctorParm.ParameterType))
 | 
			
		||||
								)
 | 
			
		||||
							)
 | 
			
		||||
						);
 | 
			
		||||
						blockExp.AddRange(new Expression[] {
 | 
			
		||||
							Expression.Assign(tryidxExp, dataIndexExp),
 | 
			
		||||
							Expression.Assign(readExp, readExpAssign),
 | 
			
		||||
							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)))
 | 
			
		||||
								Expression.Assign(dataIndexExp, readExpDataIndex)
 | 
			
		||||
							),
 | 
			
		||||
							Expression.Block(ispkExp)
 | 
			
		||||
						});
 | 
			
		||||
					}
 | 
			
		||||
					blockExp.Add(Expression.Assign(retExp, Expression.New(ctor, readExpValueParms)));
 | 
			
		||||
					blockExp.Add(
 | 
			
		||||
						Expression.IfThen(
 | 
			
		||||
							Expression.IsFalse(readpknullExp),
 | 
			
		||||
							Expression.Assign(retExp, Expression.New(ctor, readExpValueParms))
 | 
			
		||||
						)
 | 
			
		||||
					);
 | 
			
		||||
				} else {
 | 
			
		||||
					blockExp.AddRange(new Expression[] {
 | 
			
		||||
						Expression.Assign(retExp, Expression.New(ctor)),
 | 
			
		||||
@@ -825,12 +868,14 @@ namespace FreeSql.Internal {
 | 
			
		||||
						Expression.IfThen(
 | 
			
		||||
							Expression.NotEqual(indexesExp, Expression.Constant(null)),
 | 
			
		||||
							Expression.Assign(indexesLengthExp, Expression.ArrayLength(indexesExp))
 | 
			
		||||
						)
 | 
			
		||||
						),
 | 
			
		||||
						Expression.Assign(readpknullExp, Expression.Constant(false))
 | 
			
		||||
					});
 | 
			
		||||
					
 | 
			
		||||
					var props = type.GetProperties();//.ToDictionary(a => a.Name, a => a, StringComparer.CurrentCultureIgnoreCase);
 | 
			
		||||
					var propIndex = 0;
 | 
			
		||||
					foreach (var prop in props) {
 | 
			
		||||
						var ispkExp = new List<Expression>();
 | 
			
		||||
						var propGetSetMethod = prop.GetSetMethod();
 | 
			
		||||
						Expression readExpAssign = null; //加速缓存
 | 
			
		||||
						if (prop.PropertyType.IsArray) readExpAssign = Expression.New(RowInfo.Constructor,
 | 
			
		||||
@@ -842,17 +887,50 @@ namespace FreeSql.Internal {
 | 
			
		||||
							var proptypeGeneric = prop.PropertyType;
 | 
			
		||||
							if (proptypeGeneric.IsNullableType()) proptypeGeneric = proptypeGeneric.GenericTypeArguments.First();
 | 
			
		||||
							if (proptypeGeneric.IsEnum ||
 | 
			
		||||
								dicExecuteArrayRowReadClassOrTuple.ContainsKey(proptypeGeneric)) readExpAssign = Expression.New(RowInfo.Constructor,
 | 
			
		||||
								dicExecuteArrayRowReadClassOrTuple.ContainsKey(proptypeGeneric)) {
 | 
			
		||||
 | 
			
		||||
								//判断主键为空,则整个对象不读取
 | 
			
		||||
								blockExp.Add(Expression.Assign(readpkvalExp, Expression.Call(rowExp, MethodDataReaderGetValue, dataIndexExp)));
 | 
			
		||||
								if (typetb.ColumnsByCs.TryGetValue(prop.Name, out var trycol) && trycol.Attribute.IsPrimary) {
 | 
			
		||||
									ispkExp.Add(
 | 
			
		||||
										Expression.IfThen(
 | 
			
		||||
											Expression.And(
 | 
			
		||||
												Expression.IsFalse(readpknullExp),
 | 
			
		||||
												Expression.Or(
 | 
			
		||||
													Expression.Equal(readpkvalExp, Expression.Constant(DBNull.Value)),
 | 
			
		||||
													Expression.Equal(readpkvalExp, Expression.Constant(null))
 | 
			
		||||
												)
 | 
			
		||||
											),
 | 
			
		||||
											Expression.Block(
 | 
			
		||||
												Expression.Assign(readpknullExp, Expression.Constant(true)),
 | 
			
		||||
												Expression.Assign(retExp, Expression.Constant(null, type))
 | 
			
		||||
											)
 | 
			
		||||
										)
 | 
			
		||||
									);
 | 
			
		||||
								}
 | 
			
		||||
 | 
			
		||||
								readExpAssign = Expression.New(RowInfo.Constructor,
 | 
			
		||||
									GetDataReaderValueBlockExpression(prop.PropertyType, Expression.Call(rowExp, MethodDataReaderGetValue, tryidxExp)),
 | 
			
		||||
									//Expression.Call(MethodGetDataReaderValue, new Expression[] { Expression.Constant(prop.PropertyType), Expression.Call(rowExp, MethodDataReaderGetValue, tryidxExp) }),
 | 
			
		||||
									Expression.Add(tryidxExp, Expression.Constant(1))
 | 
			
		||||
							);
 | 
			
		||||
							else {
 | 
			
		||||
								);
 | 
			
		||||
							} else {
 | 
			
		||||
								++propIndex;
 | 
			
		||||
								continue;
 | 
			
		||||
								//readExpAssign = Expression.Call(MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(prop.PropertyType), indexesExp, rowExp, tryidxExp });
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						ispkExp.Add(
 | 
			
		||||
							Expression.IfThen(
 | 
			
		||||
								Expression.IsFalse(readpknullExp),
 | 
			
		||||
								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))
 | 
			
		||||
								)
 | 
			
		||||
							)
 | 
			
		||||
						);
 | 
			
		||||
						blockExp.AddRange(new Expression[] {
 | 
			
		||||
							//以下注释部分为【严格读取】,会损失一点性能,使用 select * from xxx 与属性映射赋值
 | 
			
		||||
							Expression.IfThenElse(
 | 
			
		||||
@@ -866,10 +944,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
									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.Block(ispkExp)
 | 
			
		||||
								)
 | 
			
		||||
							)
 | 
			
		||||
						});
 | 
			
		||||
@@ -880,10 +955,10 @@ namespace FreeSql.Internal {
 | 
			
		||||
					Expression.Return(returnTarget, Expression.New(RowInfo.Constructor, retExp, dataIndexExp)),
 | 
			
		||||
					Expression.Label(returnTarget, Expression.Default(typeof(RowInfo)))
 | 
			
		||||
				});
 | 
			
		||||
				return Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(
 | 
			
		||||
					Expression.Block(new[] { retExp, readExp, tryidxExp, readExpsIndex, indexesLengthExp }.Concat(readExpValueParms), blockExp), new[] { typeExp, indexesExp, rowExp, dataIndexExp }).Compile();
 | 
			
		||||
				return Expression.Lambda<Func<Type, int[], DbDataReader, int, CommonUtils, RowInfo>>(
 | 
			
		||||
					Expression.Block(new[] { retExp, readExp, tryidxExp, readpknullExp, readpkvalExp, readExpsIndex, indexesLengthExp }.Concat(readExpValueParms), blockExp), new[] { typeExp, indexesExp, rowExp, dataIndexExp, commonUtilExp }).Compile();
 | 
			
		||||
			});
 | 
			
		||||
			return func(type, indexes, row, dataIndex);
 | 
			
		||||
			return func(type, indexes, row, dataIndex, _commonUtils);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal static MethodInfo MethodExecuteArrayRowReadClassOrTuple = typeof(Utils).GetMethod("ExecuteArrayRowReadClassOrTuple", BindingFlags.Static | BindingFlags.NonPublic);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user