mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	拆分 FreeSql 按需引用
This commit is contained in:
		@@ -10,17 +10,17 @@ using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal {
 | 
			
		||||
	internal abstract class CommonExpression {
 | 
			
		||||
	public abstract class CommonExpression {
 | 
			
		||||
 | 
			
		||||
		internal CommonUtils _common;
 | 
			
		||||
		internal CommonProvider.AdoProvider _ado => _adoPriv ?? (_adoPriv = _common._orm.Ado as CommonProvider.AdoProvider);
 | 
			
		||||
		public CommonUtils _common;
 | 
			
		||||
		public CommonProvider.AdoProvider _ado => _adoPriv ?? (_adoPriv = _common._orm.Ado as CommonProvider.AdoProvider);
 | 
			
		||||
		CommonProvider.AdoProvider _adoPriv;
 | 
			
		||||
		internal CommonExpression(CommonUtils common) {
 | 
			
		||||
		public CommonExpression(CommonUtils common) {
 | 
			
		||||
			_common = common;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static ConcurrentDictionary<Type, PropertyInfo[]> _dicReadAnonymousFieldDtoPropertys = new ConcurrentDictionary<Type, PropertyInfo[]>();
 | 
			
		||||
		internal bool ReadAnonymousField(List<SelectTableInfo> _tables, StringBuilder field, ReadAnonymousTypeInfo parent, ref int index, Expression exp, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
		public bool ReadAnonymousField(List<SelectTableInfo> _tables, StringBuilder field, ReadAnonymousTypeInfo parent, ref int index, Expression exp, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
			Func<ExpTSC> getTSC = () => new ExpTSC { _tables = _tables, getSelectGroupingMapString = getSelectGroupingMapString, tbtype = SelectTableInfoType.From, isQuoteName = true, isDisableDiyParse = false, style = ExpressionStyle.Where };
 | 
			
		||||
			switch (exp.NodeType) {
 | 
			
		||||
				case ExpressionType.Quote: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand, getSelectGroupingMapString);
 | 
			
		||||
@@ -180,7 +180,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			if (index >= 0) field.Append(" as").Append(++index);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		internal object ReadAnonymous(ReadAnonymousTypeInfo parent, DbDataReader dr, ref int index, bool notRead) {
 | 
			
		||||
		public object ReadAnonymous(ReadAnonymousTypeInfo parent, DbDataReader dr, ref int index, bool notRead) {
 | 
			
		||||
			if (parent.Childs.Any() == false) {
 | 
			
		||||
				if (notRead) {
 | 
			
		||||
					++index;
 | 
			
		||||
@@ -215,7 +215,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal ColumnInfo SearchColumnByField(List<SelectTableInfo> _tables, TableInfo currentTable, string field) {
 | 
			
		||||
		public ColumnInfo SearchColumnByField(List<SelectTableInfo> _tables, TableInfo currentTable, string field) {
 | 
			
		||||
			if (_tables != null) {
 | 
			
		||||
				var testCol = _common.TrimQuoteSqlName(field).Split(new[] { '.' }, 2);
 | 
			
		||||
				if (testCol.Length == 2) {
 | 
			
		||||
@@ -232,11 +232,11 @@ namespace FreeSql.Internal {
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal string ExpressionSelectColumn_MemberAccess(List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, Expression exp, bool isQuoteName, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
		public string ExpressionSelectColumn_MemberAccess(List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, Expression exp, bool isQuoteName, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
			return ExpressionLambdaToSql(exp, new ExpTSC { _tables = _tables, _selectColumnMap = _selectColumnMap, getSelectGroupingMapString = getSelectGroupingMapString, tbtype = tbtype, isQuoteName = isQuoteName, isDisableDiyParse = false, style = ExpressionStyle.SelectColumns });
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal string[] ExpressionSelectColumns_MemberAccess_New_NewArrayInit(List<SelectTableInfo> _tables, Expression exp, bool isQuoteName, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
		public string[] ExpressionSelectColumns_MemberAccess_New_NewArrayInit(List<SelectTableInfo> _tables, Expression exp, bool isQuoteName, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
			switch (exp?.NodeType) {
 | 
			
		||||
				case ExpressionType.Quote: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as UnaryExpression)?.Operand, isQuoteName, getSelectGroupingMapString);
 | 
			
		||||
				case ExpressionType.Lambda: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as LambdaExpression)?.Body, isQuoteName, getSelectGroupingMapString);
 | 
			
		||||
@@ -276,7 +276,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			{ ExpressionType.Modulo, "%" },
 | 
			
		||||
			{ ExpressionType.Equal, "=" },
 | 
			
		||||
		};
 | 
			
		||||
		internal string ExpressionWhereLambdaNoneForeignObject(List<SelectTableInfo> _tables, TableInfo table, List<SelectColumnInfo> _selectColumnMap, Expression exp, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
		public string ExpressionWhereLambdaNoneForeignObject(List<SelectTableInfo> _tables, TableInfo table, List<SelectColumnInfo> _selectColumnMap, Expression exp, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
			var sql = ExpressionLambdaToSql(exp, new ExpTSC { _tables = _tables, _selectColumnMap = _selectColumnMap, getSelectGroupingMapString = getSelectGroupingMapString, tbtype = SelectTableInfoType.From, isQuoteName = true, isDisableDiyParse = false, style = ExpressionStyle.Where, currentTable = table });
 | 
			
		||||
			if (exp.NodeType == ExpressionType.MemberAccess && exp.Type == typeof(bool))
 | 
			
		||||
				return $"{sql} = {formatSql(true, null)}";
 | 
			
		||||
@@ -289,7 +289,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal string ExpressionWhereLambda(List<SelectTableInfo> _tables, Expression exp, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
		public string ExpressionWhereLambda(List<SelectTableInfo> _tables, Expression exp, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
			var sql = ExpressionLambdaToSql(exp, new ExpTSC { _tables = _tables, getSelectGroupingMapString = getSelectGroupingMapString, tbtype = SelectTableInfoType.From, isQuoteName = true, isDisableDiyParse = false, style = ExpressionStyle.Where });
 | 
			
		||||
			if (exp.NodeType == ExpressionType.MemberAccess && exp.Type == typeof(bool))
 | 
			
		||||
				return $"{sql} = {formatSql(true, null)}";
 | 
			
		||||
@@ -301,7 +301,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
				default: return sql;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		internal void ExpressionJoinLambda(List<SelectTableInfo> _tables, SelectTableInfoType tbtype, Expression exp, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
		public void ExpressionJoinLambda(List<SelectTableInfo> _tables, SelectTableInfoType tbtype, Expression exp, Func<Expression[], string> getSelectGroupingMapString) {
 | 
			
		||||
			var tbidx = _tables.Count;
 | 
			
		||||
			var filter = ExpressionLambdaToSql(exp, new ExpTSC { _tables = _tables, getSelectGroupingMapString = getSelectGroupingMapString, tbtype = tbtype, isQuoteName = true, isDisableDiyParse = false, style = ExpressionStyle.Where });
 | 
			
		||||
			if (exp.NodeType == ExpressionType.MemberAccess && exp.Type == typeof(bool))
 | 
			
		||||
@@ -333,7 +333,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
		internal static ConcurrentDictionary<Type, PropertyInfo> _dicNullableValueProperty = new ConcurrentDictionary<Type, PropertyInfo>();
 | 
			
		||||
		static ConcurrentDictionary<Type, Expression> _dicFreeSqlGlobalExtensionsAsSelectExpression = new ConcurrentDictionary<Type, Expression>();
 | 
			
		||||
 | 
			
		||||
		internal string ExpressionBinary(string oper, Expression leftExp, Expression rightExp, ExpTSC tsc) {
 | 
			
		||||
		public string ExpressionBinary(string oper, Expression leftExp, Expression rightExp, ExpTSC tsc) {
 | 
			
		||||
			switch (oper) {
 | 
			
		||||
				case "OR":
 | 
			
		||||
				case "|":
 | 
			
		||||
@@ -399,7 +399,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			tsc.mapType = null;
 | 
			
		||||
			return $"{left} {oper} {right}";
 | 
			
		||||
		}
 | 
			
		||||
		internal string ExpressionLambdaToSql(Expression exp, ExpTSC tsc) {
 | 
			
		||||
		public string ExpressionLambdaToSql(Expression exp, ExpTSC tsc) {
 | 
			
		||||
			if (exp == null) return "";
 | 
			
		||||
			if (tsc.isDisableDiyParse == false && _common._orm.Aop.ParseExpression != null) {
 | 
			
		||||
				var args = new Aop.ParseExpressionEventArgs(exp, ukexp => ExpressionLambdaToSql(exp, tsc.CloneDisableDiyParse()));
 | 
			
		||||
@@ -882,20 +882,20 @@ namespace FreeSql.Internal {
 | 
			
		||||
			return ExpressionBinary(tryoper, expBinary.Left, expBinary.Right, tsc);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, ExpTSC tsc);
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc);
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc);
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlCallString(MethodCallExpression exp, ExpTSC tsc);
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc);
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc);
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc);
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc);
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc);
 | 
			
		||||
		public abstract string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, ExpTSC tsc);
 | 
			
		||||
		public abstract string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc);
 | 
			
		||||
		public abstract string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc);
 | 
			
		||||
		public abstract string ExpressionLambdaToSqlCallString(MethodCallExpression exp, ExpTSC tsc);
 | 
			
		||||
		public abstract string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc);
 | 
			
		||||
		public abstract string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc);
 | 
			
		||||
		public abstract string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc);
 | 
			
		||||
		public abstract string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc);
 | 
			
		||||
		public abstract string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc);
 | 
			
		||||
 | 
			
		||||
		internal enum ExpressionStyle {
 | 
			
		||||
		public enum ExpressionStyle {
 | 
			
		||||
			Where, AsSelect, SelectColumns
 | 
			
		||||
		}
 | 
			
		||||
		internal class ExpTSC {
 | 
			
		||||
		public class ExpTSC {
 | 
			
		||||
			public List<SelectTableInfo> _tables { get; set; }
 | 
			
		||||
			public List<SelectColumnInfo> _selectColumnMap { get; set; }
 | 
			
		||||
			public Func<Expression[], string> getSelectGroupingMapString { get; set; }
 | 
			
		||||
@@ -932,7 +932,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal string formatSql(object obj, Type mapType) {
 | 
			
		||||
		public string formatSql(object obj, Type mapType) {
 | 
			
		||||
			return string.Concat(_ado.AddslashesProcessParam(obj, mapType));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using SafeObjectPool;
 | 
			
		||||
using SafeObjectPool;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
@@ -11,7 +10,7 @@ using System.Text;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
	abstract partial class AdoProvider : IAdo, IDisposable {
 | 
			
		||||
	public abstract partial class AdoProvider : IAdo, IDisposable {
 | 
			
		||||
 | 
			
		||||
		protected abstract void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex);
 | 
			
		||||
		protected abstract DbCommand CreateCommand();
 | 
			
		||||
@@ -24,16 +23,12 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
		public ObjectPool<DbConnection> MasterPool { get; protected set; }
 | 
			
		||||
		public List<ObjectPool<DbConnection>> SlavePools { get; } = new List<ObjectPool<DbConnection>>();
 | 
			
		||||
		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();
 | 
			
		||||
 | 
			
		||||
		public AdoProvider(ICache cache, ILogger log, DataType dataType) {
 | 
			
		||||
			this._cache = cache;
 | 
			
		||||
			this._log = log;
 | 
			
		||||
		public AdoProvider(DataType dataType) {
 | 
			
		||||
			this.DataType = dataType;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -43,7 +38,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			if (IsTracePerformance) {
 | 
			
		||||
				TimeSpan ts = DateTime.Now.Subtract(dt);
 | 
			
		||||
				if (e == null && ts.TotalMilliseconds > 100)
 | 
			
		||||
					_log.LogWarning(logtxt.Insert(0, $"{pool?.Policy.Name}(执行SQL)语句耗时过长{ts.TotalMilliseconds}ms\r\n{cmd.CommandText}\r\n").ToString());
 | 
			
		||||
					Trace.WriteLine(logtxt.Insert(0, $"{pool?.Policy.Name}(执行SQL)语句耗时过长{ts.TotalMilliseconds}ms\r\n{cmd.CommandText}\r\n").ToString());
 | 
			
		||||
				else
 | 
			
		||||
					logtxt.Insert(0, $"{pool?.Policy.Name}(执行SQL)耗时{ts.TotalMilliseconds}ms\r\n{cmd.CommandText}\r\n").ToString();
 | 
			
		||||
			}
 | 
			
		||||
@@ -59,7 +54,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
				log.Append(parm.ParameterName.PadRight(20, ' ')).Append(" = ").Append((parm.Value ?? DBNull.Value) == DBNull.Value ? "NULL" : parm.Value).Append("\r\n");
 | 
			
		||||
 | 
			
		||||
			log.Append(e.Message);
 | 
			
		||||
			_log.LogError(log.ToString());
 | 
			
		||||
			Trace.WriteLine(log.ToString());
 | 
			
		||||
 | 
			
		||||
			if (cmd.Transaction != null) {
 | 
			
		||||
				var curTran = TransactionCurrentThread;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,8 @@
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using SafeObjectPool;
 | 
			
		||||
using SafeObjectPool;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Data.Common;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
 | 
			
		||||
@@ -29,24 +28,6 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
		public DbTransaction TransactionCurrentThread => _trans.TryGetValue(Thread.CurrentThread.ManagedThreadId, out var conn) && conn.Transaction?.Connection != null ? conn.Transaction : null;
 | 
			
		||||
 | 
			
		||||
		private Dictionary<int, List<string>> _preRemoveKeys = new Dictionary<int, List<string>>();
 | 
			
		||||
		private object _preRemoveKeys_lock = new object();
 | 
			
		||||
		public string[] PreRemove(params string[] key) {
 | 
			
		||||
			var tid = Thread.CurrentThread.ManagedThreadId;
 | 
			
		||||
			List<string> keys = null;
 | 
			
		||||
			if (key == null || key.Any() == false) return _preRemoveKeys.TryGetValue(tid, out keys) ? keys.ToArray() : new string[0];
 | 
			
		||||
			_log.LogDebug($"线程{tid}事务预删除 {JsonConvert.SerializeObject(key)}");
 | 
			
		||||
			if (_preRemoveKeys.TryGetValue(tid, out keys) == false)
 | 
			
		||||
				lock (_preRemoveKeys_lock)
 | 
			
		||||
					if (_preRemoveKeys.TryGetValue(tid, out keys) == false) {
 | 
			
		||||
						_preRemoveKeys.Add(tid, keys = new List<string>(key));
 | 
			
		||||
						return key;
 | 
			
		||||
					}
 | 
			
		||||
			keys.AddRange(key);
 | 
			
		||||
			return keys.ToArray();
 | 
			
		||||
		}
 | 
			
		||||
		public void TransactionPreRemoveCache(params string[] key) => PreRemove(key);
 | 
			
		||||
 | 
			
		||||
		public void BeginTransaction(TimeSpan timeout) {
 | 
			
		||||
			if (TransactionCurrentThread != null) return;
 | 
			
		||||
 | 
			
		||||
@@ -58,7 +39,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
				conn = MasterPool.Get();
 | 
			
		||||
				tran = new Transaction2(conn, conn.Value.BeginTransaction(), timeout);
 | 
			
		||||
			} catch(Exception ex) {
 | 
			
		||||
				_log.LogError($"数据库出错(开启事务){ex.Message} \r\n{ex.StackTrace}");
 | 
			
		||||
				Trace.WriteLine($"数据库出错(开启事务){ex.Message} \r\n{ex.StackTrace}");
 | 
			
		||||
				MasterPool.Return(conn);
 | 
			
		||||
				throw ex;
 | 
			
		||||
			}
 | 
			
		||||
@@ -84,22 +65,15 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
					if (_trans.ContainsKey(tran.Conn.LastGetThreadId))
 | 
			
		||||
						_trans.Remove(tran.Conn.LastGetThreadId);
 | 
			
		||||
 | 
			
		||||
			var removeKeys = PreRemove();
 | 
			
		||||
			if (_preRemoveKeys.ContainsKey(tran.Conn.LastGetThreadId))
 | 
			
		||||
				lock (_preRemoveKeys_lock)
 | 
			
		||||
					if (_preRemoveKeys.ContainsKey(tran.Conn.LastGetThreadId))
 | 
			
		||||
						_preRemoveKeys.Remove(tran.Conn.LastGetThreadId);
 | 
			
		||||
 | 
			
		||||
			Exception ex = null;
 | 
			
		||||
			var f001 = isCommit ? "提交" : "回滚";
 | 
			
		||||
			try {
 | 
			
		||||
				_log.LogDebug($"线程{tran.Conn.LastGetThreadId}事务{f001},批量删除缓存key {Newtonsoft.Json.JsonConvert.SerializeObject(removeKeys)}");
 | 
			
		||||
				_cache.Remove(removeKeys);
 | 
			
		||||
				Trace.WriteLine($"线程{tran.Conn.LastGetThreadId}事务{f001}");
 | 
			
		||||
				if (isCommit) tran.Transaction.Commit();
 | 
			
		||||
				else tran.Transaction.Rollback();
 | 
			
		||||
			} catch (Exception ex2) {
 | 
			
		||||
				ex = ex2;
 | 
			
		||||
				_log.LogError($"数据库出错({f001}事务):{ex.Message} {ex.StackTrace}");
 | 
			
		||||
				Trace.WriteLine($"数据库出错({f001}事务):{ex.Message} {ex.StackTrace}");
 | 
			
		||||
			} finally {
 | 
			
		||||
				ReturnConnection(MasterPool, tran.Conn, ex); //MasterPool.Return(tran.Conn, ex);
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ using System.Linq.Expressions;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
	class AopProvider : IAop {
 | 
			
		||||
	public class AopProvider : IAop {
 | 
			
		||||
		public EventHandler<Aop.ToListEventArgs> ToList { get; set; }
 | 
			
		||||
		public EventHandler<Aop.WhereEventArgs> Where { get; set; }
 | 
			
		||||
		public EventHandler<Aop.ParseExpressionEventArgs> ParseExpression { get; set; }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,186 +0,0 @@
 | 
			
		||||
using Microsoft.Extensions.Caching.Distributed;
 | 
			
		||||
using Microsoft.Extensions.Caching.Memory;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Microsoft.Extensions.Options;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
	class CacheProvider : ICache, IDisposable {
 | 
			
		||||
 | 
			
		||||
		public IDistributedCache Cache { get; private set; }
 | 
			
		||||
		private bool CacheSupportMultiRemove = false;
 | 
			
		||||
		private static DateTime dt1970 = new DateTime(1970, 1, 1);
 | 
			
		||||
 | 
			
		||||
		public CacheProvider(IDistributedCache cache, ILogger log) {
 | 
			
		||||
			if (cache == null) cache = new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions { }));
 | 
			
		||||
			Cache = cache;
 | 
			
		||||
			var key1 = $"testCacheSupportMultiRemoveFreeSql{Guid.NewGuid().ToString("N")}";
 | 
			
		||||
			var key2 = $"testCacheSupportMultiRemoveFreeSql{Guid.NewGuid().ToString("N")}";
 | 
			
		||||
			Cache.Set(key1, new byte[] { 65 });
 | 
			
		||||
			Cache.Set(key2, new byte[] { 65 });
 | 
			
		||||
			try { Cache.Remove($"{key1}|{key2}"); } catch { } // redis-cluster 不允许执行 multi keys 命令
 | 
			
		||||
			CacheSupportMultiRemove = Cache.Get(key1) == null && cache.Get(key2) == null;
 | 
			
		||||
			if (CacheSupportMultiRemove == false) {
 | 
			
		||||
				//log.LogWarning("FreeSql Warning: 低性能, IDistributedCache 没实现批量删除缓存 Cache.Remove(\"key1|key2\").");
 | 
			
		||||
				Remove(key1, key2);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		~CacheProvider() {
 | 
			
		||||
			this.Dispose();
 | 
			
		||||
		}
 | 
			
		||||
		bool _isdisposed = false;
 | 
			
		||||
		public void Dispose() {
 | 
			
		||||
			if (_isdisposed) return;
 | 
			
		||||
 | 
			
		||||
			Cache = null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Func<object, string> Serialize { get; set; }
 | 
			
		||||
		public Func<string, Type, object> Deserialize { get; set; }
 | 
			
		||||
 | 
			
		||||
		Func<JsonSerializerSettings> JsonSerializerSettings = () => {
 | 
			
		||||
			var st = new JsonSerializerSettings();
 | 
			
		||||
			st.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
 | 
			
		||||
			st.DateFormatHandling = DateFormatHandling.IsoDateFormat;
 | 
			
		||||
			st.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
 | 
			
		||||
			return st;
 | 
			
		||||
		};
 | 
			
		||||
		string SerializeObject(object value) {
 | 
			
		||||
			if (Serialize != null) return Serialize(value);
 | 
			
		||||
			return JsonConvert.SerializeObject(value, this.JsonSerializerSettings());
 | 
			
		||||
		}
 | 
			
		||||
		T DeserializeObject<T>(string value) {
 | 
			
		||||
			if (Deserialize != null) return (T) Deserialize(value, typeof(T));
 | 
			
		||||
			return JsonConvert.DeserializeObject<T>(value, this.JsonSerializerSettings());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Set<T>(string key, T data, int timeoutSeconds = 0) {
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) return;
 | 
			
		||||
			Cache.Set(key, Encoding.UTF8.GetBytes(this.SerializeObject(data)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
 | 
			
		||||
		}
 | 
			
		||||
		public T Get<T>(string key) {
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) return default(T);
 | 
			
		||||
			var value = Cache.Get(key);
 | 
			
		||||
			if (value == null) return default(T);
 | 
			
		||||
			return this.DeserializeObject<T>(Encoding.UTF8.GetString(value));
 | 
			
		||||
		}
 | 
			
		||||
		public string Get(string key) {
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) return null;
 | 
			
		||||
			var value = Cache.Get(key);
 | 
			
		||||
			if (value == null) return null;
 | 
			
		||||
			return Encoding.UTF8.GetString(value);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		async public Task SetAsync<T>(string key, T data, int timeoutSeconds = 0) {
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) return;
 | 
			
		||||
			await Cache.SetAsync(key, Encoding.UTF8.GetBytes(this.SerializeObject(data)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
 | 
			
		||||
		}
 | 
			
		||||
		async public Task<T> GetAsync<T>(string key) {
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) return default(T);
 | 
			
		||||
			var value = await Cache.GetAsync(key);
 | 
			
		||||
			if (value == null) return default(T);
 | 
			
		||||
			return this.DeserializeObject<T>(Encoding.UTF8.GetString(value));
 | 
			
		||||
		}
 | 
			
		||||
		async public Task<string> GetAsync(string key) {
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) return null;
 | 
			
		||||
			var value = await Cache.GetAsync(key);
 | 
			
		||||
			if (value == null) return null;
 | 
			
		||||
			return Encoding.UTF8.GetString(value);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Remove(params string[] keys) {
 | 
			
		||||
			if (keys == null || keys.Length == 0) return;
 | 
			
		||||
			var keysDistinct = keys.Distinct();
 | 
			
		||||
			if (CacheSupportMultiRemove) Cache.Remove(string.Join("|", keysDistinct));
 | 
			
		||||
			else foreach (var key in keysDistinct) Cache.Remove(key);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		async public Task RemoveAsync(params string[] keys) {
 | 
			
		||||
			if (keys == null || keys.Length == 0) return;
 | 
			
		||||
			var keysDistinct = keys.Distinct();
 | 
			
		||||
			if (CacheSupportMultiRemove) await Cache.RemoveAsync(string.Join("|", keysDistinct));
 | 
			
		||||
			else foreach (var key in keysDistinct) await Cache.RemoveAsync(key);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T Shell<T>(string key, int timeoutSeconds, Func<T> getData) {
 | 
			
		||||
			if (timeoutSeconds <= 0) return getData();
 | 
			
		||||
			if (Cache == null) throw new Exception("缓存实现 IDistributedCache 为 null");
 | 
			
		||||
			var cacheValue = Cache.Get(key);
 | 
			
		||||
			if (cacheValue != null) {
 | 
			
		||||
				try {
 | 
			
		||||
					var txt = Encoding.UTF8.GetString(cacheValue);
 | 
			
		||||
					return DeserializeObject<T>(txt);
 | 
			
		||||
				} catch {
 | 
			
		||||
					Cache.Remove(key);
 | 
			
		||||
					throw;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			var ret = getData();
 | 
			
		||||
			Cache.Set(key, Encoding.UTF8.GetBytes(SerializeObject(ret)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T Shell<T>(string key, string field, int timeoutSeconds, Func<T> getData) {
 | 
			
		||||
			if (timeoutSeconds <= 0) return getData();
 | 
			
		||||
			if (Cache == null) throw new Exception("缓存实现 IDistributedCache 为 null");
 | 
			
		||||
			var hashkey = $"{key}:{field}";
 | 
			
		||||
			var cacheValue = Cache.Get(hashkey);
 | 
			
		||||
			if (cacheValue != null) {
 | 
			
		||||
				try {
 | 
			
		||||
					var txt = Encoding.UTF8.GetString(cacheValue);
 | 
			
		||||
					var value = DeserializeObject<(T, long)>(txt);
 | 
			
		||||
					if (DateTime.Now.Subtract(dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds) return value.Item1;
 | 
			
		||||
				} catch {
 | 
			
		||||
					Cache.Remove(hashkey);
 | 
			
		||||
					throw;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			var ret = (getData(), (long) DateTime.Now.Subtract(dt1970).TotalSeconds);
 | 
			
		||||
			Cache.Set(hashkey, Encoding.UTF8.GetBytes(SerializeObject(ret)));
 | 
			
		||||
			return ret.Item1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		async public Task<T> ShellAsync<T>(string key, int timeoutSeconds, Func<Task<T>> getDataAsync) {
 | 
			
		||||
			if (timeoutSeconds <= 0) return await getDataAsync();
 | 
			
		||||
			if (Cache == null) throw new Exception("缓存实现 IDistributedCache 为 null");
 | 
			
		||||
			var cacheValue = await Cache.GetAsync(key);
 | 
			
		||||
			if (cacheValue != null) {
 | 
			
		||||
				try {
 | 
			
		||||
					var txt = Encoding.UTF8.GetString(cacheValue);
 | 
			
		||||
					return DeserializeObject<T>(txt);
 | 
			
		||||
				} catch {
 | 
			
		||||
					await Cache.RemoveAsync(key);
 | 
			
		||||
					throw;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			var ret = await getDataAsync();
 | 
			
		||||
			await Cache.SetAsync(key, Encoding.UTF8.GetBytes(SerializeObject(ret)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		async public Task<T> ShellAsync<T>(string key, string field, int timeoutSeconds, Func<Task<T>> getDataAsync) {
 | 
			
		||||
			if (timeoutSeconds <= 0) return await getDataAsync();
 | 
			
		||||
			if (Cache == null) throw new Exception("缓存实现 IDistributedCache 为 null");
 | 
			
		||||
			var hashkey = $"{key}:{field}";
 | 
			
		||||
			var cacheValue = await Cache.GetAsync(hashkey);
 | 
			
		||||
			if (cacheValue != null) {
 | 
			
		||||
				try {
 | 
			
		||||
					var txt = Encoding.UTF8.GetString(cacheValue);
 | 
			
		||||
					var value = DeserializeObject<(T, long)>(txt);
 | 
			
		||||
					if (DateTime.Now.Subtract(dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds) return value.Item1;
 | 
			
		||||
				} catch {
 | 
			
		||||
					await Cache.RemoveAsync(hashkey);
 | 
			
		||||
					throw;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			var ret = (await getDataAsync(), (long) DateTime.Now.Subtract(dt1970).TotalSeconds);
 | 
			
		||||
			await Cache.SetAsync(hashkey, Encoding.UTF8.GetBytes(SerializeObject(ret)));
 | 
			
		||||
			return ret.Item1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -9,7 +9,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract partial class DeleteProvider<T1> : IDelete<T1> where T1 : class {
 | 
			
		||||
	public abstract partial class DeleteProvider<T1> : IDelete<T1> where T1 : class {
 | 
			
		||||
		protected IFreeSql _orm;
 | 
			
		||||
		protected CommonUtils _commonUtils;
 | 
			
		||||
		protected CommonExpression _commonExpression;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract partial class InsertProvider<T1> : IInsert<T1> where T1 : class {
 | 
			
		||||
	public abstract partial class InsertProvider<T1> : IInsert<T1> where T1 : class {
 | 
			
		||||
		protected IFreeSql _orm;
 | 
			
		||||
		protected CommonUtils _commonUtils;
 | 
			
		||||
		protected CommonExpression _commonExpression;
 | 
			
		||||
@@ -69,7 +69,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		#region 参数化数据限制,或values数量限制
 | 
			
		||||
		internal List<T1>[] SplitSource(int valuesLimit, int parameterLimit) {
 | 
			
		||||
		protected List<T1>[] SplitSource(int valuesLimit, int parameterLimit) {
 | 
			
		||||
			valuesLimit = valuesLimit - 1;
 | 
			
		||||
			parameterLimit = parameterLimit - 1;
 | 
			
		||||
			if (_source == null || _source.Any() == false) return new List<T1>[0];
 | 
			
		||||
@@ -101,7 +101,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
				return ret;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		internal int SplitExecuteAffrows(int valuesLimit, int parameterLimit) {
 | 
			
		||||
		protected int SplitExecuteAffrows(int valuesLimit, int parameterLimit) {
 | 
			
		||||
			var ss = SplitSource(valuesLimit, parameterLimit);
 | 
			
		||||
			var ret = 0;
 | 
			
		||||
			if (ss.Any() == false) {
 | 
			
		||||
@@ -137,7 +137,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async internal Task<int> SplitExecuteAffrowsAsync(int valuesLimit, int parameterLimit) {
 | 
			
		||||
		async protected Task<int> SplitExecuteAffrowsAsync(int valuesLimit, int parameterLimit) {
 | 
			
		||||
			var ss = SplitSource(valuesLimit, parameterLimit);
 | 
			
		||||
			var ret = 0;
 | 
			
		||||
			if (ss.Any() == false) {
 | 
			
		||||
@@ -173,7 +173,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		internal long SplitExecuteIdentity(int valuesLimit, int parameterLimit) {
 | 
			
		||||
		protected long SplitExecuteIdentity(int valuesLimit, int parameterLimit) {
 | 
			
		||||
			var ss = SplitSource(valuesLimit, parameterLimit);
 | 
			
		||||
			long ret = 0;
 | 
			
		||||
			if (ss.Any() == false) {
 | 
			
		||||
@@ -211,7 +211,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async internal Task<long> SplitExecuteIdentityAsync(int valuesLimit, int parameterLimit) {
 | 
			
		||||
		async protected Task<long> SplitExecuteIdentityAsync(int valuesLimit, int parameterLimit) {
 | 
			
		||||
			var ss = SplitSource(valuesLimit, parameterLimit);
 | 
			
		||||
			long ret = 0;
 | 
			
		||||
			if (ss.Any() == false) {
 | 
			
		||||
@@ -249,7 +249,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		internal List<T1> SplitExecuteInserted(int valuesLimit, int parameterLimit) {
 | 
			
		||||
		protected List<T1> SplitExecuteInserted(int valuesLimit, int parameterLimit) {
 | 
			
		||||
			var ss = SplitSource(valuesLimit, parameterLimit);
 | 
			
		||||
			var ret = new List<T1>();
 | 
			
		||||
			if (ss.Any() == false) {
 | 
			
		||||
@@ -285,7 +285,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async internal Task<List<T1>> SplitExecuteInsertedAsync(int valuesLimit, int parameterLimit) {
 | 
			
		||||
		async protected Task<List<T1>> SplitExecuteInsertedAsync(int valuesLimit, int parameterLimit) {
 | 
			
		||||
			var ss = SplitSource(valuesLimit, parameterLimit);
 | 
			
		||||
			var ret = new List<T1>();
 | 
			
		||||
			if (ss.Any() == false) {
 | 
			
		||||
@@ -323,7 +323,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
		}
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		internal int RawExecuteAffrows() {
 | 
			
		||||
		protected int RawExecuteAffrows() {
 | 
			
		||||
			var sql = ToSql();
 | 
			
		||||
			var before = new Aop.CurdBeforeEventArgs(_table.Type, Aop.CurdType.Insert, sql, _params);
 | 
			
		||||
			_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
@@ -341,7 +341,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		async internal Task<int> RawExecuteAffrowsAsync() {
 | 
			
		||||
		async protected Task<int> RawExecuteAffrowsAsync() {
 | 
			
		||||
			var sql = ToSql();
 | 
			
		||||
			var before = new Aop.CurdBeforeEventArgs(_table.Type, Aop.CurdType.Insert, sql, _params);
 | 
			
		||||
			_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
@@ -359,10 +359,10 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		internal abstract long RawExecuteIdentity();
 | 
			
		||||
		internal abstract Task<long> RawExecuteIdentityAsync();
 | 
			
		||||
		internal abstract List<T1> RawExecuteInserted();
 | 
			
		||||
		internal abstract Task<List<T1>> RawExecuteInsertedAsync();
 | 
			
		||||
		protected abstract long RawExecuteIdentity();
 | 
			
		||||
		protected abstract Task<long> RawExecuteIdentityAsync();
 | 
			
		||||
		protected abstract List<T1> RawExecuteInserted();
 | 
			
		||||
		protected abstract Task<List<T1>> RawExecuteInsertedAsync();
 | 
			
		||||
 | 
			
		||||
		public abstract int ExecuteAffrows();
 | 
			
		||||
		public abstract Task<int> ExecuteAffrowsAsync();
 | 
			
		||||
 
 | 
			
		||||
@@ -14,16 +14,15 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract class Select0Provider<TSelect, T1> : ISelect0<TSelect, T1> where TSelect : class where T1 : class {
 | 
			
		||||
	public abstract class Select0Provider<TSelect, T1> : ISelect0<TSelect, T1> where TSelect : class where T1 : class {
 | 
			
		||||
 | 
			
		||||
		protected int _limit, _skip;
 | 
			
		||||
		protected string _select = "SELECT ", _orderby, _groupby, _having;
 | 
			
		||||
		protected StringBuilder _where = new StringBuilder();
 | 
			
		||||
		protected List<DbParameter> _params = new List<DbParameter>();
 | 
			
		||||
		internal List<SelectTableInfo> _tables = new List<SelectTableInfo>();
 | 
			
		||||
		protected List<SelectTableInfo> _tables = new List<SelectTableInfo>();
 | 
			
		||||
		protected List<Func<Type, string, string>> _tableRules = new List<Func<Type, string, string>>();
 | 
			
		||||
		protected StringBuilder _join = new StringBuilder();
 | 
			
		||||
		protected (int seconds, string key) _cache = (0, null);
 | 
			
		||||
		protected IFreeSql _orm;
 | 
			
		||||
		protected CommonUtils _commonUtils;
 | 
			
		||||
		protected CommonExpression _commonExpression;
 | 
			
		||||
@@ -34,7 +33,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
		protected bool _distinct;
 | 
			
		||||
		protected Expression _selectExpression;
 | 
			
		||||
 | 
			
		||||
		internal static void CopyData(Select0Provider<TSelect, T1> from, object to, ReadOnlyCollection<ParameterExpression> lambParms) {
 | 
			
		||||
		public static void CopyData(Select0Provider<TSelect, T1> from, object to, ReadOnlyCollection<ParameterExpression> lambParms) {
 | 
			
		||||
			var toType = to?.GetType();
 | 
			
		||||
			if (toType == null) return;
 | 
			
		||||
			toType.GetField("_limit", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._limit);
 | 
			
		||||
@@ -63,7 +62,6 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			}
 | 
			
		||||
			toType.GetField("_tableRules", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._tableRules);
 | 
			
		||||
			toType.GetField("_join", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new StringBuilder().Append(from._join.ToString()));
 | 
			
		||||
			toType.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._cache);
 | 
			
		||||
			//toType.GetField("_orm", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._orm);
 | 
			
		||||
			//toType.GetField("_commonUtils", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._commonUtils);
 | 
			
		||||
			//toType.GetField("_commonExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._commonExpression);
 | 
			
		||||
@@ -109,10 +107,6 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			return (await this.ToListAsync<int>("1")).FirstOrDefault() == 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public TSelect Caching(int seconds, string key = null) {
 | 
			
		||||
			_cache = (seconds, key);
 | 
			
		||||
			return this as TSelect;
 | 
			
		||||
		}
 | 
			
		||||
		public long Count() => this.ToList<int>("count(1)").FirstOrDefault();
 | 
			
		||||
		async public Task<long> CountAsync() => (await this.ToListAsync<int>("count(1)")).FirstOrDefault();
 | 
			
		||||
 | 
			
		||||
@@ -220,166 +214,142 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
		public DataTable ToDataTable(string field = null) {
 | 
			
		||||
			var sql = this.ToSql(field);
 | 
			
		||||
			if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = sql;
 | 
			
		||||
 | 
			
		||||
			return _orm.Cache.Shell(_cache.key, _cache.seconds, () => {
 | 
			
		||||
				var dbParms = _params.ToArray();
 | 
			
		||||
				var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
				_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
				DataTable ret = null;
 | 
			
		||||
				Exception exception = null;
 | 
			
		||||
				try {
 | 
			
		||||
					ret = _orm.Ado.ExecuteDataTable(_connection, _transaction, CommandType.Text, sql, dbParms);
 | 
			
		||||
				} catch (Exception ex) {
 | 
			
		||||
					exception = ex;
 | 
			
		||||
					throw ex;
 | 
			
		||||
				} finally {
 | 
			
		||||
					var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
					_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
				}
 | 
			
		||||
				return ret;
 | 
			
		||||
			});
 | 
			
		||||
			var dbParms = _params.ToArray();
 | 
			
		||||
			var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
			_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
			DataTable ret = null;
 | 
			
		||||
			Exception exception = null;
 | 
			
		||||
			try {
 | 
			
		||||
				ret = _orm.Ado.ExecuteDataTable(_connection, _transaction, CommandType.Text, sql, dbParms);
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				exception = ex;
 | 
			
		||||
				throw ex;
 | 
			
		||||
			} finally {
 | 
			
		||||
				var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
				_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
			}
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		public Task<DataTable> ToDataTableAsync(string field = null) {
 | 
			
		||||
		async public Task<DataTable> ToDataTableAsync(string field = null) {
 | 
			
		||||
			var sql = this.ToSql(field);
 | 
			
		||||
			if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = sql;
 | 
			
		||||
 | 
			
		||||
			return _orm.Cache.ShellAsync(_cache.key, _cache.seconds, async () => {
 | 
			
		||||
				var dbParms = _params.ToArray();
 | 
			
		||||
				var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
				_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
				DataTable ret = null;
 | 
			
		||||
				Exception exception = null;
 | 
			
		||||
				try {
 | 
			
		||||
					ret = await _orm.Ado.ExecuteDataTableAsync(_connection, _transaction, CommandType.Text, sql, dbParms);
 | 
			
		||||
				} catch (Exception ex) {
 | 
			
		||||
					exception = ex;
 | 
			
		||||
					throw ex;
 | 
			
		||||
				} finally {
 | 
			
		||||
					var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
					_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
				}
 | 
			
		||||
				return ret;
 | 
			
		||||
			});
 | 
			
		||||
			var dbParms = _params.ToArray();
 | 
			
		||||
			var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
			_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
			DataTable ret = null;
 | 
			
		||||
			Exception exception = null;
 | 
			
		||||
			try {
 | 
			
		||||
				ret = await _orm.Ado.ExecuteDataTableAsync(_connection, _transaction, CommandType.Text, sql, dbParms);
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				exception = ex;
 | 
			
		||||
				throw ex;
 | 
			
		||||
			} finally {
 | 
			
		||||
				var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
				_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
			}
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<TTuple> ToList<TTuple>(string field) {
 | 
			
		||||
			var sql = this.ToSql(field);
 | 
			
		||||
			if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = sql;
 | 
			
		||||
 | 
			
		||||
			return _orm.Cache.Shell(_cache.key, _cache.seconds, () => {
 | 
			
		||||
				var type = typeof(TTuple);
 | 
			
		||||
				var dbParms = _params.ToArray();
 | 
			
		||||
				var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
				_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
				var ret = new List<TTuple>();
 | 
			
		||||
				var flagStr = $"ToListField:{field}";
 | 
			
		||||
				Exception exception = null;
 | 
			
		||||
				try {
 | 
			
		||||
					_orm.Ado.ExecuteReader(_connection, _transaction, dr => {
 | 
			
		||||
						var read = Utils.ExecuteArrayRowReadClassOrTuple(flagStr, type, null, dr, 0, _commonUtils);
 | 
			
		||||
						ret.Add((TTuple)read.Value);
 | 
			
		||||
					}, CommandType.Text, sql, dbParms);
 | 
			
		||||
				} catch (Exception ex) {
 | 
			
		||||
					exception = ex;
 | 
			
		||||
					throw ex;
 | 
			
		||||
				} finally {
 | 
			
		||||
					var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
					_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
				}
 | 
			
		||||
				return ret;
 | 
			
		||||
			});
 | 
			
		||||
			var type = typeof(TTuple);
 | 
			
		||||
			var dbParms = _params.ToArray();
 | 
			
		||||
			var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
			_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
			var ret = new List<TTuple>();
 | 
			
		||||
			var flagStr = $"ToListField:{field}";
 | 
			
		||||
			Exception exception = null;
 | 
			
		||||
			try {
 | 
			
		||||
				_orm.Ado.ExecuteReader(_connection, _transaction, dr => {
 | 
			
		||||
					var read = Utils.ExecuteArrayRowReadClassOrTuple(flagStr, type, null, dr, 0, _commonUtils);
 | 
			
		||||
					ret.Add((TTuple)read.Value);
 | 
			
		||||
				}, CommandType.Text, sql, dbParms);
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				exception = ex;
 | 
			
		||||
				throw ex;
 | 
			
		||||
			} finally {
 | 
			
		||||
				var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
				_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
			}
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		public Task<List<TTuple>> ToListAsync<TTuple>(string field) {
 | 
			
		||||
		async public Task<List<TTuple>> ToListAsync<TTuple>(string field) {
 | 
			
		||||
			var sql = this.ToSql(field);
 | 
			
		||||
			if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = sql;
 | 
			
		||||
 | 
			
		||||
			return _orm.Cache.ShellAsync(_cache.key, _cache.seconds, async () => {
 | 
			
		||||
				var type = typeof(TTuple);
 | 
			
		||||
				var dbParms = _params.ToArray();
 | 
			
		||||
				var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
				_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
				var ret = new List<TTuple>();
 | 
			
		||||
				var flagStr = $"ToListField:{field}";
 | 
			
		||||
				Exception exception = null;
 | 
			
		||||
				try {
 | 
			
		||||
					await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, dr => {
 | 
			
		||||
						var read = Utils.ExecuteArrayRowReadClassOrTuple(flagStr, type, null, dr, 0, _commonUtils);
 | 
			
		||||
						ret.Add((TTuple)read.Value);
 | 
			
		||||
						return Task.CompletedTask;
 | 
			
		||||
					}, CommandType.Text, sql, dbParms);
 | 
			
		||||
				} catch (Exception ex) {
 | 
			
		||||
					exception = ex;
 | 
			
		||||
					throw ex;
 | 
			
		||||
				} finally {
 | 
			
		||||
					var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
					_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
				}
 | 
			
		||||
				return ret;
 | 
			
		||||
			});
 | 
			
		||||
			var type = typeof(TTuple);
 | 
			
		||||
			var dbParms = _params.ToArray();
 | 
			
		||||
			var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
			_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
			var ret = new List<TTuple>();
 | 
			
		||||
			var flagStr = $"ToListField:{field}";
 | 
			
		||||
			Exception exception = null;
 | 
			
		||||
			try {
 | 
			
		||||
				await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, dr => {
 | 
			
		||||
					var read = Utils.ExecuteArrayRowReadClassOrTuple(flagStr, type, null, dr, 0, _commonUtils);
 | 
			
		||||
					ret.Add((TTuple)read.Value);
 | 
			
		||||
					return Task.CompletedTask;
 | 
			
		||||
				}, CommandType.Text, sql, dbParms);
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				exception = ex;
 | 
			
		||||
				throw ex;
 | 
			
		||||
			} finally {
 | 
			
		||||
				var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
				_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
			}
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		internal List<T1> ToListAfPrivate(string sql, GetAllFieldExpressionTreeInfo af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData) {
 | 
			
		||||
			if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = $"{sql}{string.Join("|", _params.Select(a => a.Value))}";
 | 
			
		||||
 | 
			
		||||
			return _orm.Cache.Shell(_cache.key, _cache.seconds, () => {
 | 
			
		||||
				var dbParms = _params.ToArray();
 | 
			
		||||
				var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
				_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
				var ret = new List<T1>();
 | 
			
		||||
				Exception exception = null;
 | 
			
		||||
				try {
 | 
			
		||||
					_orm.Ado.ExecuteReader(_connection, _transaction, dr => {
 | 
			
		||||
						ret.Add(af.Read(_orm, dr));
 | 
			
		||||
						if (otherData != null) {
 | 
			
		||||
							var idx = af.FieldCount - 1;
 | 
			
		||||
							foreach (var other in otherData)
 | 
			
		||||
								other.retlist.Add(_commonExpression.ReadAnonymous(other.read, dr, ref idx, false));
 | 
			
		||||
						}
 | 
			
		||||
					}, CommandType.Text, sql, dbParms);
 | 
			
		||||
				} catch (Exception ex) {
 | 
			
		||||
					exception = ex;
 | 
			
		||||
					throw ex;
 | 
			
		||||
				} finally {
 | 
			
		||||
					var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
					_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
				}
 | 
			
		||||
				while (_includeToList.Any()) _includeToList.Dequeue()?.Invoke(ret);
 | 
			
		||||
				_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
			
		||||
				_trackToList?.Invoke(ret);
 | 
			
		||||
				return ret;
 | 
			
		||||
			});
 | 
			
		||||
			var dbParms = _params.ToArray();
 | 
			
		||||
			var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
			_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
			var ret = new List<T1>();
 | 
			
		||||
			Exception exception = null;
 | 
			
		||||
			try {
 | 
			
		||||
				_orm.Ado.ExecuteReader(_connection, _transaction, dr => {
 | 
			
		||||
					ret.Add(af.Read(_orm, dr));
 | 
			
		||||
					if (otherData != null) {
 | 
			
		||||
						var idx = af.FieldCount - 1;
 | 
			
		||||
						foreach (var other in otherData)
 | 
			
		||||
							other.retlist.Add(_commonExpression.ReadAnonymous(other.read, dr, ref idx, false));
 | 
			
		||||
					}
 | 
			
		||||
				}, CommandType.Text, sql, dbParms);
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				exception = ex;
 | 
			
		||||
				throw ex;
 | 
			
		||||
			} finally {
 | 
			
		||||
				var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
				_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
			}
 | 
			
		||||
			while (_includeToList.Any()) _includeToList.Dequeue()?.Invoke(ret);
 | 
			
		||||
			_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
			
		||||
			_trackToList?.Invoke(ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async internal Task<List<T1>> ToListAfPrivateAsync(string sql, GetAllFieldExpressionTreeInfo af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData) {
 | 
			
		||||
			if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = $"{sql}{string.Join("|", _params.Select(a => a.Value))}";
 | 
			
		||||
 | 
			
		||||
			return await _orm.Cache.ShellAsync(_cache.key, _cache.seconds, async () => {
 | 
			
		||||
				var dbParms = _params.ToArray();
 | 
			
		||||
				var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
				_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
				var ret = new List<T1>();
 | 
			
		||||
				Exception exception = null;
 | 
			
		||||
				try {
 | 
			
		||||
					await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, dr => {
 | 
			
		||||
						ret.Add(af.Read(_orm, dr));
 | 
			
		||||
						if (otherData != null) {
 | 
			
		||||
							var idx = af.FieldCount - 1;
 | 
			
		||||
							foreach (var other in otherData)
 | 
			
		||||
								other.retlist.Add(_commonExpression.ReadAnonymous(other.read, dr, ref idx, false));
 | 
			
		||||
						}
 | 
			
		||||
						return Task.CompletedTask;
 | 
			
		||||
					}, CommandType.Text, sql, dbParms);
 | 
			
		||||
				} catch (Exception ex) {
 | 
			
		||||
					exception = ex;
 | 
			
		||||
					throw ex;
 | 
			
		||||
				} finally {
 | 
			
		||||
					var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
					_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
				}
 | 
			
		||||
				while (_includeToList.Any()) _includeToList.Dequeue()?.Invoke(ret);
 | 
			
		||||
				_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
			
		||||
				_trackToList?.Invoke(ret);
 | 
			
		||||
				return ret;
 | 
			
		||||
			});
 | 
			
		||||
			var dbParms = _params.ToArray();
 | 
			
		||||
			var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
			_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
			var ret = new List<T1>();
 | 
			
		||||
			Exception exception = null;
 | 
			
		||||
			try {
 | 
			
		||||
				await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, dr => {
 | 
			
		||||
					ret.Add(af.Read(_orm, dr));
 | 
			
		||||
					if (otherData != null) {
 | 
			
		||||
						var idx = af.FieldCount - 1;
 | 
			
		||||
						foreach (var other in otherData)
 | 
			
		||||
							other.retlist.Add(_commonExpression.ReadAnonymous(other.read, dr, ref idx, false));
 | 
			
		||||
					}
 | 
			
		||||
					return Task.CompletedTask;
 | 
			
		||||
				}, CommandType.Text, sql, dbParms);
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				exception = ex;
 | 
			
		||||
				throw ex;
 | 
			
		||||
			} finally {
 | 
			
		||||
				var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
				_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
			}
 | 
			
		||||
			while (_includeToList.Any()) _includeToList.Dequeue()?.Invoke(ret);
 | 
			
		||||
			_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
			
		||||
			_trackToList?.Invoke(ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		internal List<T1> ToListPrivate(GetAllFieldExpressionTreeInfo af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData) {
 | 
			
		||||
			string sql = null;
 | 
			
		||||
@@ -427,60 +397,52 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
		protected List<TReturn> ToListMapReader<TReturn>((ReadAnonymousTypeInfo map, string field) af) {
 | 
			
		||||
			var sql = this.ToSql(af.field);
 | 
			
		||||
			if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = $"{sql}{string.Join("|", _params.Select(a => a.Value))}";
 | 
			
		||||
 | 
			
		||||
			return _orm.Cache.Shell(_cache.key, _cache.seconds, () => {
 | 
			
		||||
				var type = typeof(TReturn);
 | 
			
		||||
				var dbParms = _params.ToArray();
 | 
			
		||||
				var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
				_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
				var ret = new List<TReturn>();
 | 
			
		||||
				Exception exception = null;
 | 
			
		||||
				try {
 | 
			
		||||
					_orm.Ado.ExecuteReader(_connection, _transaction, dr => {
 | 
			
		||||
						var index = -1;
 | 
			
		||||
						ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index, false));
 | 
			
		||||
					}, CommandType.Text, sql, dbParms);
 | 
			
		||||
				} catch (Exception ex) {
 | 
			
		||||
					exception = ex;
 | 
			
		||||
					throw ex;
 | 
			
		||||
				} finally {
 | 
			
		||||
					var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
					_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
				}
 | 
			
		||||
				_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
			
		||||
				_trackToList?.Invoke(ret);
 | 
			
		||||
				return ret;
 | 
			
		||||
			});
 | 
			
		||||
			var type = typeof(TReturn);
 | 
			
		||||
			var dbParms = _params.ToArray();
 | 
			
		||||
			var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
			_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
			var ret = new List<TReturn>();
 | 
			
		||||
			Exception exception = null;
 | 
			
		||||
			try {
 | 
			
		||||
				_orm.Ado.ExecuteReader(_connection, _transaction, dr => {
 | 
			
		||||
					var index = -1;
 | 
			
		||||
					ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index, false));
 | 
			
		||||
				}, CommandType.Text, sql, dbParms);
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				exception = ex;
 | 
			
		||||
				throw ex;
 | 
			
		||||
			} finally {
 | 
			
		||||
				var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
				_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
			}
 | 
			
		||||
			_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
			
		||||
			_trackToList?.Invoke(ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async protected Task<List<TReturn>> ToListMapReaderAsync<TReturn>((ReadAnonymousTypeInfo map, string field) af) {
 | 
			
		||||
			var sql = this.ToSql(af.field);
 | 
			
		||||
			if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = $"{sql}{string.Join("|", _params.Select(a => a.Value))}";
 | 
			
		||||
 | 
			
		||||
			return await _orm.Cache.ShellAsync(_cache.key, _cache.seconds, async () => {
 | 
			
		||||
				var type = typeof(TReturn);
 | 
			
		||||
				var dbParms = _params.ToArray();
 | 
			
		||||
				var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
				_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
				var ret = new List<TReturn>();
 | 
			
		||||
				Exception exception = null;
 | 
			
		||||
				try {
 | 
			
		||||
					await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, dr => {
 | 
			
		||||
						var index = -1;
 | 
			
		||||
						ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index, false));
 | 
			
		||||
						return Task.CompletedTask;
 | 
			
		||||
					}, CommandType.Text, sql, dbParms);
 | 
			
		||||
				} catch (Exception ex) {
 | 
			
		||||
					exception = ex;
 | 
			
		||||
					throw ex;
 | 
			
		||||
				} finally {
 | 
			
		||||
					var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
					_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
				}
 | 
			
		||||
				_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
			
		||||
				_trackToList?.Invoke(ret);
 | 
			
		||||
				return ret;
 | 
			
		||||
			});
 | 
			
		||||
			var type = typeof(TReturn);
 | 
			
		||||
			var dbParms = _params.ToArray();
 | 
			
		||||
			var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, Aop.CurdType.Select, sql, dbParms);
 | 
			
		||||
			_orm.Aop.CurdBefore?.Invoke(this, before);
 | 
			
		||||
			var ret = new List<TReturn>();
 | 
			
		||||
			Exception exception = null;
 | 
			
		||||
			try {
 | 
			
		||||
				await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, dr => {
 | 
			
		||||
					var index = -1;
 | 
			
		||||
					ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index, false));
 | 
			
		||||
					return Task.CompletedTask;
 | 
			
		||||
				}, CommandType.Text, sql, dbParms);
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				exception = ex;
 | 
			
		||||
				throw ex;
 | 
			
		||||
			} finally {
 | 
			
		||||
				var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
			
		||||
				_orm.Aop.CurdAfter?.Invoke(this, after);
 | 
			
		||||
			}
 | 
			
		||||
			_orm.Aop.ToList?.Invoke(this, new Aop.ToListEventArgs(ret));
 | 
			
		||||
			_trackToList?.Invoke(ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		protected (ReadAnonymousTypeInfo map, string field) GetExpressionField(Expression newexp) {
 | 
			
		||||
			var map = new ReadAnonymousTypeInfo();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract class Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
 | 
			
		||||
	public abstract class Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
 | 
			
		||||
			where T1 : class
 | 
			
		||||
			where T2 : class
 | 
			
		||||
			where T3 : class
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract class Select1Provider<T1> : Select0Provider<ISelect<T1>, T1>, ISelect<T1>
 | 
			
		||||
	public abstract class Select1Provider<T1> : Select0Provider<ISelect<T1>, T1>, ISelect<T1>
 | 
			
		||||
			where T1 : class {
 | 
			
		||||
		public Select1Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract class Select2Provider<T1, T2> : Select0Provider<ISelect<T1, T2>, T1>, ISelect<T1, T2>
 | 
			
		||||
	public abstract class Select2Provider<T1, T2> : Select0Provider<ISelect<T1, T2>, T1>, ISelect<T1, T2>
 | 
			
		||||
			where T1 : class
 | 
			
		||||
			where T2 : class {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract class Select3Provider<T1, T2, T3> : Select0Provider<ISelect<T1, T2, T3>, T1>, ISelect<T1, T2, T3>
 | 
			
		||||
	public abstract class Select3Provider<T1, T2, T3> : Select0Provider<ISelect<T1, T2, T3>, T1>, ISelect<T1, T2, T3>
 | 
			
		||||
			where T1 : class
 | 
			
		||||
			where T2 : class
 | 
			
		||||
			where T3 : class {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract class Select4Provider<T1, T2, T3, T4> : Select0Provider<ISelect<T1, T2, T3, T4>, T1>, ISelect<T1, T2, T3, T4>
 | 
			
		||||
	public abstract class Select4Provider<T1, T2, T3, T4> : Select0Provider<ISelect<T1, T2, T3, T4>, T1>, ISelect<T1, T2, T3, T4>
 | 
			
		||||
			where T1 : class
 | 
			
		||||
			where T2 : class
 | 
			
		||||
			where T3 : class
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract class Select5Provider<T1, T2, T3, T4, T5> : Select0Provider<ISelect<T1, T2, T3, T4, T5>, T1>, ISelect<T1, T2, T3, T4, T5>
 | 
			
		||||
	public abstract class Select5Provider<T1, T2, T3, T4, T5> : Select0Provider<ISelect<T1, T2, T3, T4, T5>, T1>, ISelect<T1, T2, T3, T4, T5>
 | 
			
		||||
			where T1 : class
 | 
			
		||||
			where T2 : class
 | 
			
		||||
			where T3 : class
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract class Select6Provider<T1, T2, T3, T4, T5, T6> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6>, T1>, ISelect<T1, T2, T3, T4, T5, T6>
 | 
			
		||||
	public abstract class Select6Provider<T1, T2, T3, T4, T5, T6> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6>, T1>, ISelect<T1, T2, T3, T4, T5, T6>
 | 
			
		||||
			where T1 : class
 | 
			
		||||
			where T2 : class
 | 
			
		||||
			where T3 : class
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract class Select7Provider<T1, T2, T3, T4, T5, T6, T7> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7>
 | 
			
		||||
	public abstract class Select7Provider<T1, T2, T3, T4, T5, T6, T7> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7>
 | 
			
		||||
			where T1 : class
 | 
			
		||||
			where T2 : class
 | 
			
		||||
			where T3 : class
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract class Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8>
 | 
			
		||||
	public abstract class Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8>
 | 
			
		||||
			where T1 : class
 | 
			
		||||
			where T2 : class
 | 
			
		||||
			where T3 : class
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract class Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>
 | 
			
		||||
	public abstract class Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>
 | 
			
		||||
			where T1 : class
 | 
			
		||||
			where T2 : class
 | 
			
		||||
			where T3 : class
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
	class SelectGroupingProvider<TKey, TValue> : ISelectGrouping<TKey, TValue> {
 | 
			
		||||
	public class SelectGroupingProvider<TKey, TValue> : ISelectGrouping<TKey, TValue> {
 | 
			
		||||
 | 
			
		||||
		internal object _select;
 | 
			
		||||
		internal ReadAnonymousTypeInfo _map;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
 | 
			
		||||
	abstract partial class UpdateProvider<T1> : IUpdate<T1> where T1 : class {
 | 
			
		||||
	public abstract partial class UpdateProvider<T1> : IUpdate<T1> where T1 : class {
 | 
			
		||||
		protected IFreeSql _orm;
 | 
			
		||||
		protected CommonUtils _commonUtils;
 | 
			
		||||
		protected CommonExpression _commonExpression;
 | 
			
		||||
@@ -106,7 +106,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
				return ret;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		internal int SplitExecuteAffrows(int valuesLimit, int parameterLimit) {
 | 
			
		||||
		protected int SplitExecuteAffrows(int valuesLimit, int parameterLimit) {
 | 
			
		||||
			var ss = SplitSource(valuesLimit, parameterLimit);
 | 
			
		||||
			var ret = 0;
 | 
			
		||||
			if (ss.Length <= 1) {
 | 
			
		||||
@@ -138,7 +138,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async internal Task<int> SplitExecuteAffrowsAsync(int valuesLimit, int parameterLimit) {
 | 
			
		||||
		async protected Task<int> SplitExecuteAffrowsAsync(int valuesLimit, int parameterLimit) {
 | 
			
		||||
			var ss = SplitSource(valuesLimit, parameterLimit);
 | 
			
		||||
			var ret = 0;
 | 
			
		||||
			if (ss.Length <= 1) {
 | 
			
		||||
@@ -170,7 +170,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		internal List<T1> SplitExecuteUpdated(int valuesLimit, int parameterLimit) {
 | 
			
		||||
		protected List<T1> SplitExecuteUpdated(int valuesLimit, int parameterLimit) {
 | 
			
		||||
			var ss = SplitSource(valuesLimit, parameterLimit);
 | 
			
		||||
			var ret = new List<T1>();
 | 
			
		||||
			if (ss.Length <= 1) {
 | 
			
		||||
@@ -202,7 +202,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async internal Task<List<T1>> SplitExecuteUpdatedAsync(int valuesLimit, int parameterLimit) {
 | 
			
		||||
		async protected Task<List<T1>> SplitExecuteUpdatedAsync(int valuesLimit, int parameterLimit) {
 | 
			
		||||
			var ss = SplitSource(valuesLimit, parameterLimit);
 | 
			
		||||
			var ret = new List<T1>();
 | 
			
		||||
			if (ss.Length <= 1) {
 | 
			
		||||
@@ -236,7 +236,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
		}
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		internal int RawExecuteAffrows() {
 | 
			
		||||
		protected int RawExecuteAffrows() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
			var dbParms = _params.Concat(_paramsSource).ToArray();
 | 
			
		||||
@@ -257,7 +257,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		async internal Task<int> RawExecuteAffrowsAsync() {
 | 
			
		||||
		async protected Task<int> RawExecuteAffrowsAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
			var dbParms = _params.Concat(_paramsSource).ToArray();
 | 
			
		||||
@@ -278,8 +278,8 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		internal abstract List<T1> RawExecuteUpdated();
 | 
			
		||||
		internal abstract Task<List<T1>> RawExecuteUpdatedAsync();
 | 
			
		||||
		protected abstract List<T1> RawExecuteUpdated();
 | 
			
		||||
		protected abstract Task<List<T1>> RawExecuteUpdatedAsync();
 | 
			
		||||
 | 
			
		||||
		public abstract int ExecuteAffrows();
 | 
			
		||||
		public abstract Task<int> ExecuteAffrowsAsync();
 | 
			
		||||
 
 | 
			
		||||
@@ -2,43 +2,46 @@
 | 
			
		||||
using FreeSql.DatabaseModel;
 | 
			
		||||
using FreeSql.Extensions.EntityUtil;
 | 
			
		||||
using FreeSql.Internal.Model;
 | 
			
		||||
using SafeObjectPool;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Data.Common;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal {
 | 
			
		||||
	internal abstract class CommonUtils {
 | 
			
		||||
	public abstract class CommonUtils {
 | 
			
		||||
 | 
			
		||||
		internal abstract string GetNoneParamaterSqlValue(List<DbParameter> specialParams, Type type, object value);
 | 
			
		||||
		internal abstract DbParameter AppendParamter(List<DbParameter> _params, string parameterName, Type type, object value);
 | 
			
		||||
		internal abstract DbParameter[] GetDbParamtersByObject(string sql, object obj);
 | 
			
		||||
		internal abstract string FormatSql(string sql, params object[] args);
 | 
			
		||||
		internal abstract string QuoteSqlName(string name);
 | 
			
		||||
		internal abstract string TrimQuoteSqlName(string name);
 | 
			
		||||
		internal abstract string QuoteParamterName(string name);
 | 
			
		||||
		internal abstract string IsNull(string sql, object value);
 | 
			
		||||
		internal abstract string StringConcat(string[] objs, Type[] types);
 | 
			
		||||
		internal abstract string Mod(string left, string right, Type leftType, Type rightType);
 | 
			
		||||
		internal abstract string QuoteWriteParamter(Type type, string paramterName);
 | 
			
		||||
		internal abstract string QuoteReadColumn(Type type, string columnName);
 | 
			
		||||
		public abstract string GetNoneParamaterSqlValue(List<DbParameter> specialParams, Type type, object value);
 | 
			
		||||
		public abstract DbParameter AppendParamter(List<DbParameter> _params, string parameterName, Type type, object value);
 | 
			
		||||
		public abstract DbParameter[] GetDbParamtersByObject(string sql, object obj);
 | 
			
		||||
		public abstract string FormatSql(string sql, params object[] args);
 | 
			
		||||
		public abstract string QuoteSqlName(string name);
 | 
			
		||||
		public abstract string TrimQuoteSqlName(string name);
 | 
			
		||||
		public abstract string QuoteParamterName(string name);
 | 
			
		||||
		public abstract string IsNull(string sql, object value);
 | 
			
		||||
		public abstract string StringConcat(string[] objs, Type[] types);
 | 
			
		||||
		public abstract string Mod(string left, string right, Type leftType, Type rightType);
 | 
			
		||||
		public abstract string QuoteWriteParamter(Type type, string paramterName);
 | 
			
		||||
		public abstract string QuoteReadColumn(Type type, string columnName);
 | 
			
		||||
 | 
			
		||||
		internal IFreeSql _orm { get; set; }
 | 
			
		||||
		internal ICodeFirst CodeFirst => _orm.CodeFirst;
 | 
			
		||||
		internal TableInfo GetTableByEntity(Type entity) => Utils.GetTableByEntity(entity, this);
 | 
			
		||||
		internal List<DbTableInfo> dbTables { get; set; }
 | 
			
		||||
		internal object dbTablesLock = new object();
 | 
			
		||||
		public IFreeSql _orm { get; set; }
 | 
			
		||||
		public ICodeFirst CodeFirst => _orm.CodeFirst;
 | 
			
		||||
		public TableInfo GetTableByEntity(Type entity) => Utils.GetTableByEntity(entity, this);
 | 
			
		||||
		public List<DbTableInfo> dbTables { get; set; }
 | 
			
		||||
		public object dbTablesLock = new object();
 | 
			
		||||
 | 
			
		||||
		public CommonUtils(IFreeSql orm) {
 | 
			
		||||
			_orm = orm;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ConcurrentDictionary<Type, TableAttribute> dicConfigEntity = new ConcurrentDictionary<Type, TableAttribute>();
 | 
			
		||||
		internal ICodeFirst ConfigEntity<T>(Action<TableFluent<T>> entity) {
 | 
			
		||||
		public ICodeFirst ConfigEntity<T>(Action<TableFluent<T>> entity) {
 | 
			
		||||
			if (entity == null) return _orm.CodeFirst;
 | 
			
		||||
			var type = typeof(T);
 | 
			
		||||
			var table = dicConfigEntity.GetOrAdd(type, new TableAttribute());
 | 
			
		||||
@@ -47,7 +50,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			Utils.RemoveTableByEntity(type, this); //remove cache
 | 
			
		||||
			return _orm.CodeFirst;
 | 
			
		||||
		}
 | 
			
		||||
		internal ICodeFirst ConfigEntity(Type type, Action<TableFluent> entity) {
 | 
			
		||||
		public ICodeFirst ConfigEntity(Type type, Action<TableFluent> entity) {
 | 
			
		||||
			if (entity == null) return _orm.CodeFirst;
 | 
			
		||||
			var table = dicConfigEntity.GetOrAdd(type, new TableAttribute());
 | 
			
		||||
			var fluent = new TableFluent(type, table);
 | 
			
		||||
@@ -55,10 +58,10 @@ namespace FreeSql.Internal {
 | 
			
		||||
			Utils.RemoveTableByEntity(type, this); //remove cache
 | 
			
		||||
			return _orm.CodeFirst;
 | 
			
		||||
		}
 | 
			
		||||
		internal TableAttribute GetConfigEntity(Type type) {
 | 
			
		||||
		public TableAttribute GetConfigEntity(Type type) {
 | 
			
		||||
			return dicConfigEntity.TryGetValue(type, out var trytb) ? trytb : null;
 | 
			
		||||
		}
 | 
			
		||||
		internal TableAttribute GetEntityTableAttribute(Type type) {
 | 
			
		||||
		public TableAttribute GetEntityTableAttribute(Type type) {
 | 
			
		||||
			TableAttribute attr = null;
 | 
			
		||||
			if (_orm.Aop.ConfigEntity != null) {
 | 
			
		||||
				var aope = new Aop.ConfigEntityEventArgs(type);
 | 
			
		||||
@@ -84,7 +87,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			if (!string.IsNullOrEmpty(attr.SelectFilter)) return attr;
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
		internal ColumnAttribute GetEntityColumnAttribute(Type type, PropertyInfo proto) {
 | 
			
		||||
		public ColumnAttribute GetEntityColumnAttribute(Type type, PropertyInfo proto) {
 | 
			
		||||
			ColumnAttribute attr = null;
 | 
			
		||||
			if (_orm.Aop.ConfigEntityProperty != null) {
 | 
			
		||||
				var aope = new Aop.ConfigEntityPropertyEventArgs(type, proto);
 | 
			
		||||
@@ -137,7 +140,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal string WhereObject(TableInfo table, string aliasAndDot, object dywhere) {
 | 
			
		||||
		public string WhereObject(TableInfo table, string aliasAndDot, object dywhere) {
 | 
			
		||||
			if (dywhere == null) return "";
 | 
			
		||||
			var type = dywhere.GetType();
 | 
			
		||||
			var primarys = table.Primarys;
 | 
			
		||||
@@ -182,7 +185,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal string WhereItems<TEntity>(TableInfo table, string aliasAndDot, IEnumerable<TEntity> items) {
 | 
			
		||||
		public string WhereItems<TEntity>(TableInfo table, string aliasAndDot, IEnumerable<TEntity> items) {
 | 
			
		||||
			if (items == null || items.Any() == false) return null;
 | 
			
		||||
			if (table.Primarys.Any() == false) return null;
 | 
			
		||||
			var its = items.Where(a => a != null).ToArray();
 | 
			
		||||
@@ -231,5 +234,39 @@ namespace FreeSql.Internal {
 | 
			
		||||
			}
 | 
			
		||||
			return iidx == 1 ? sb.Remove(0, 5).Remove(sb.Length - 1, 1).ToString() : sb.Remove(0, 4).ToString();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static void PrevReheatConnectionPool(ObjectPool<DbConnection> pool, int minPoolSize) {
 | 
			
		||||
			if (minPoolSize <= 0) minPoolSize = Math.Min(5, pool.Policy.PoolSize);
 | 
			
		||||
			if (minPoolSize > pool.Policy.PoolSize) minPoolSize = pool.Policy.PoolSize;
 | 
			
		||||
			var initTestOk = true;
 | 
			
		||||
			var initStartTime = DateTime.Now;
 | 
			
		||||
			var initConns = new ConcurrentBag<Object<DbConnection>>();
 | 
			
		||||
 | 
			
		||||
			try {
 | 
			
		||||
				var conn = pool.Get();
 | 
			
		||||
				initConns.Add(conn);
 | 
			
		||||
				pool.Policy.OnCheckAvailable(conn);
 | 
			
		||||
			} catch {
 | 
			
		||||
				initTestOk = false; //预热一次失败,后面将不进行
 | 
			
		||||
			}
 | 
			
		||||
			for (var a = 1; initTestOk && a < minPoolSize; a += 10) {
 | 
			
		||||
				if (initStartTime.Subtract(DateTime.Now).TotalSeconds > 3) break; //预热耗时超过3秒,退出
 | 
			
		||||
				var b = Math.Min(minPoolSize - a, 10); //每10个预热
 | 
			
		||||
				var initTasks = new Task[b];
 | 
			
		||||
				for (var c = 0; c < b; c++) {
 | 
			
		||||
					initTasks[c] = Task.Run(() => {
 | 
			
		||||
						try {
 | 
			
		||||
							var conn = pool.Get();
 | 
			
		||||
							initConns.Add(conn);
 | 
			
		||||
							pool.Policy.OnCheckAvailable(conn);
 | 
			
		||||
						} catch {
 | 
			
		||||
							initTestOk = false;  //有失败,下一组退出预热
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
				}
 | 
			
		||||
				Task.WaitAll(initTasks);
 | 
			
		||||
			}
 | 
			
		||||
			while (initConns.TryTake(out var conn)) pool.Return(conn);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.Model {
 | 
			
		||||
	class ReadAnonymousTypeInfo {
 | 
			
		||||
	public class ReadAnonymousTypeInfo {
 | 
			
		||||
		public PropertyInfo Property { get; set; }
 | 
			
		||||
		public string CsName { get; set; }
 | 
			
		||||
		public Type CsType { get; set; }
 | 
			
		||||
@@ -15,5 +15,5 @@ namespace FreeSql.Internal.Model {
 | 
			
		||||
		public List<ReadAnonymousTypeInfo> Childs = new List<ReadAnonymousTypeInfo>();
 | 
			
		||||
		public TableInfo Table { get; set; }
 | 
			
		||||
	}
 | 
			
		||||
	enum ReadAnonymousTypeInfoConsturctorType { Arguments, Properties }
 | 
			
		||||
	public enum ReadAnonymousTypeInfoConsturctorType { Arguments, Properties }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.Model {
 | 
			
		||||
	class SelectColumnInfo {
 | 
			
		||||
	public class SelectColumnInfo {
 | 
			
		||||
		public ColumnInfo Column { get; set; }
 | 
			
		||||
		public SelectTableInfo Table { get; set; }
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.Model {
 | 
			
		||||
	class SelectTableInfo {
 | 
			
		||||
	public class SelectTableInfo {
 | 
			
		||||
		public TableInfo Table { get; set; }
 | 
			
		||||
 | 
			
		||||
		private string _alias;
 | 
			
		||||
@@ -18,5 +18,5 @@ namespace FreeSql.Internal.Model {
 | 
			
		||||
		public ParameterExpression Parameter { get; set; }
 | 
			
		||||
		public SelectTableInfoType Type { get; set; }
 | 
			
		||||
	}
 | 
			
		||||
	enum SelectTableInfoType { From, LeftJoin, InnerJoin, RightJoin, Parent }
 | 
			
		||||
	public enum SelectTableInfoType { From, LeftJoin, InnerJoin, RightJoin, Parent }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
using FreeSql.DataAnnotations;
 | 
			
		||||
using FreeSql.Internal.Model;
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
@@ -637,8 +636,9 @@ namespace FreeSql.Internal {
 | 
			
		||||
			if (overrieds > 0) {
 | 
			
		||||
				cscode.AppendLine("}");
 | 
			
		||||
				Assembly assembly = null;
 | 
			
		||||
				if (MethodLazyLoadingComplier.Value == null) throw new Exception("【延时加载】功能需要安装 FreeSql.Extensions.LazyLoading.dll,可前往 nuget 下载");
 | 
			
		||||
				try {
 | 
			
		||||
					assembly = Generator.TemplateEngin._compiler.Value.CompileCode(cscode.ToString());
 | 
			
		||||
					assembly = MethodLazyLoadingComplier.Value.Invoke(null, new object[] { cscode.ToString() }) as Assembly;
 | 
			
		||||
				} catch (Exception ex) {
 | 
			
		||||
					throw new Exception($"【延时加载】{trytbTypeName} 编译错误:{ex.Message}\r\n\r\n{cscode}");
 | 
			
		||||
				}
 | 
			
		||||
@@ -651,8 +651,12 @@ namespace FreeSql.Internal {
 | 
			
		||||
 | 
			
		||||
			return tbc.TryGetValue(entity, out var trytb2) ? trytb2 : trytb;
 | 
			
		||||
		}
 | 
			
		||||
		static Lazy<MethodInfo> MethodLazyLoadingComplier = new Lazy<MethodInfo>(() => {
 | 
			
		||||
			var type = Type.GetType("FreeSql.Extensions.LazyLoading.LazyLoadingComplier,FreeSql.Extensions.LazyLoading");
 | 
			
		||||
			return type.GetMethod("CompileCode");
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		internal static T[] GetDbParamtersByObject<T>(string sql, object obj, string paramPrefix, Func<string, Type, object, T> constructorParamter) {
 | 
			
		||||
		public static T[] GetDbParamtersByObject<T>(string sql, object obj, string paramPrefix, Func<string, Type, object, T> constructorParamter) {
 | 
			
		||||
			if (string.IsNullOrEmpty(sql) || obj == null) return new T[0];
 | 
			
		||||
			var ttype = typeof(T);
 | 
			
		||||
			var type = obj.GetType();
 | 
			
		||||
@@ -668,7 +672,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			return ret.ToArray();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal static Dictionary<Type, bool> dicExecuteArrayRowReadClassOrTuple = new Dictionary<Type, bool> {
 | 
			
		||||
		public static Dictionary<Type, bool> dicExecuteArrayRowReadClassOrTuple = new Dictionary<Type, bool> {
 | 
			
		||||
			[typeof(bool)] = true,
 | 
			
		||||
			[typeof(sbyte)] = true,
 | 
			
		||||
			[typeof(short)] = true,
 | 
			
		||||
@@ -837,12 +841,14 @@ namespace FreeSql.Internal {
 | 
			
		||||
 | 
			
		||||
				if (type == typeof(object) && indexes != null) {
 | 
			
		||||
					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;
 | 
			
		||||
						//dynamic expando = new DynamicDictionary(); //动态类型字段 可读可写
 | 
			
		||||
						var expandodic = new Dictionary<string, object>();// (IDictionary<string, object>)expando;
 | 
			
		||||
						var fc = row2.FieldCount;
 | 
			
		||||
						for (var a = 0; a < fc; a++)
 | 
			
		||||
							//expando[row2.GetName(a)] = row2.GetValue(a);
 | 
			
		||||
							expandodic.Add(row2.GetName(a), row2.GetValue(a));
 | 
			
		||||
						return new RowInfo(expando, fc);
 | 
			
		||||
						//expando = expandodic;
 | 
			
		||||
						return new RowInfo(expandodic, fc);
 | 
			
		||||
					};
 | 
			
		||||
					return dynamicFunc;// Expression.Lambda<Func<Type, int[], DbDataReader, int, RowInfo>>(null);
 | 
			
		||||
				}
 | 
			
		||||
@@ -1092,14 +1098,10 @@ namespace FreeSql.Internal {
 | 
			
		||||
		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 MethodArrayGetLength = typeof(Array).GetMethod("GetLength", new[] { typeof(int) });
 | 
			
		||||
		static MethodInfo MethodMygisGeometryParse = typeof(MygisGeometry).GetMethod("Parse", new[] { typeof(string) });
 | 
			
		||||
		static MethodInfo MethodGuidTryParse = typeof(Guid).GetMethod("TryParse", new[] { typeof(string), typeof(Guid).MakeByRefType() });
 | 
			
		||||
		static MethodInfo MethodEnumParse = typeof(Enum).GetMethod("Parse", new[] { typeof(Type), typeof(string), typeof(bool) });
 | 
			
		||||
		static MethodInfo MethodConvertChangeType = typeof(Convert).GetMethod("ChangeType", new[] { typeof(object), typeof(Type) });
 | 
			
		||||
		static MethodInfo MethodTimeSpanFromSeconds = typeof(TimeSpan).GetMethod("FromSeconds");
 | 
			
		||||
		static MethodInfo MethodJTokenParse = typeof(JToken).GetMethod("Parse", new[] { typeof(string) });
 | 
			
		||||
		static MethodInfo MethodJObjectParse = typeof(JObject).GetMethod("Parse", new[] { typeof(string) });
 | 
			
		||||
		static MethodInfo MethodJArrayParse = typeof(JArray).GetMethod("Parse", new[] { typeof(string) });
 | 
			
		||||
		static MethodInfo MethodSByteTryParse = typeof(sbyte).GetMethod("TryParse", new[] { typeof(string), typeof(sbyte).MakeByRefType() });
 | 
			
		||||
		static MethodInfo MethodShortTryParse = typeof(short).GetMethod("TryParse", new[] { typeof(string), typeof(short).MakeByRefType() });
 | 
			
		||||
		static MethodInfo MethodIntTryParse = typeof(int).GetMethod("TryParse", new[] { typeof(string), typeof(int).MakeByRefType() });
 | 
			
		||||
@@ -1116,6 +1118,8 @@ namespace FreeSql.Internal {
 | 
			
		||||
		static MethodInfo MethodDateTimeOffsetTryParse = typeof(DateTimeOffset).GetMethod("TryParse", new[] { typeof(string), typeof(DateTimeOffset).MakeByRefType() });
 | 
			
		||||
		static MethodInfo MethodToString = typeof(Utils).GetMethod("ToStringConcat", BindingFlags.NonPublic | BindingFlags.Static, null, new[] { typeof(object) }, null);
 | 
			
		||||
		static MethodInfo MethodBigIntegerParse = typeof(Utils).GetMethod("ToBigInteger", BindingFlags.NonPublic | BindingFlags.Static, null, new[] { typeof(string) }, null);
 | 
			
		||||
 | 
			
		||||
		public static ConcurrentBag<Func<LabelTarget, Expression, string, Expression>> GetDataReaderValueBlockExpressionSwitchTypeFullName = new ConcurrentBag<Func<LabelTarget, Expression, string, Expression>>();
 | 
			
		||||
		public static Expression GetDataReaderValueBlockExpression(Type type, Expression value) {
 | 
			
		||||
			var returnTarget = Expression.Label(typeof(object));
 | 
			
		||||
			var valueExp = Expression.Variable(typeof(object), "locvalue");
 | 
			
		||||
@@ -1177,16 +1181,6 @@ namespace FreeSql.Internal {
 | 
			
		||||
							   }
 | 
			
		||||
						   );
 | 
			
		||||
						break;
 | 
			
		||||
					case "MygisPoint": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisPoint)));
 | 
			
		||||
					case "MygisLineString": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisLineString)));
 | 
			
		||||
					case "MygisPolygon": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisPolygon)));
 | 
			
		||||
					case "MygisMultiPoint": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisMultiPoint)));
 | 
			
		||||
					case "MygisMultiLineString": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisMultiLineString)));
 | 
			
		||||
					case "MygisMultiPolygon": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisMultiPolygon)));
 | 
			
		||||
					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 "Newtonsoft.Json.Linq.JArray": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJArrayParse, Expression.Convert(valueExp, typeof(string))), typeof(JArray)));
 | 
			
		||||
					case "Npgsql.LegacyPostgis.PostgisGeometry": return Expression.Return(returnTarget, valueExp);
 | 
			
		||||
					case "System.Numerics.BigInteger": return Expression.Return(returnTarget, Expression.Convert(Expression.Call(MethodBigIntegerParse, Expression.Call(MethodToString, valueExp)), typeof(object)));
 | 
			
		||||
					case "System.TimeSpan":
 | 
			
		||||
						ParameterExpression tryparseVarTsExp, valueStrExp;
 | 
			
		||||
@@ -1373,6 +1367,12 @@ namespace FreeSql.Internal {
 | 
			
		||||
							typeof(object))
 | 
			
		||||
						);
 | 
			
		||||
						break;
 | 
			
		||||
					default:
 | 
			
		||||
						foreach (var switchFunc in GetDataReaderValueBlockExpressionSwitchTypeFullName) {
 | 
			
		||||
							var switchFuncRet = switchFunc(returnTarget, valueExp, type.FullName);
 | 
			
		||||
							if (switchFuncRet != null) return switchFuncRet;
 | 
			
		||||
						}
 | 
			
		||||
						break;
 | 
			
		||||
				}
 | 
			
		||||
				Expression switchExp = null;
 | 
			
		||||
				if (tryparseExp != null)
 | 
			
		||||
@@ -1437,45 +1437,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			});
 | 
			
		||||
			return func(value);
 | 
			
		||||
		}
 | 
			
		||||
		internal static object GetDataReaderValue22(Type type, object value) {
 | 
			
		||||
			if (value == null || value == DBNull.Value) return Activator.CreateInstance(type);
 | 
			
		||||
			if (type.FullName == "System.Byte[]") return value;
 | 
			
		||||
			if (type.IsArray) {
 | 
			
		||||
				var elementType = type.GetElementType();
 | 
			
		||||
				var valueArr = value as Array;
 | 
			
		||||
				if (elementType == valueArr.GetType().GetElementType()) return value;
 | 
			
		||||
				var len = valueArr.GetLength(0);
 | 
			
		||||
				var ret = Array.CreateInstance(elementType, len);
 | 
			
		||||
				for (var a = 0; a < len; a++) {
 | 
			
		||||
					var item = valueArr.GetValue(a);
 | 
			
		||||
					ret.SetValue(GetDataReaderValue22(elementType, item), a);
 | 
			
		||||
				}
 | 
			
		||||
				return ret;
 | 
			
		||||
			}
 | 
			
		||||
			if (type.IsNullableType()) type = type.GenericTypeArguments.First();
 | 
			
		||||
			if (type.IsEnum) return Enum.Parse(type, string.Concat(value), true);
 | 
			
		||||
			switch (type.FullName) {
 | 
			
		||||
				case "System.Guid":
 | 
			
		||||
					if (value.GetType() != type) return Guid.TryParse(string.Concat(value), out var tryguid) ? tryguid : Guid.Empty;
 | 
			
		||||
					return value;
 | 
			
		||||
				case "MygisPoint": return MygisPoint.Parse(string.Concat(value)) as MygisPoint;
 | 
			
		||||
				case "MygisLineString": return MygisLineString.Parse(string.Concat(value)) as MygisLineString;
 | 
			
		||||
				case "MygisPolygon": return MygisPolygon.Parse(string.Concat(value)) as MygisPolygon;
 | 
			
		||||
				case "MygisMultiPoint": return MygisMultiPoint.Parse(string.Concat(value)) as MygisMultiPoint;
 | 
			
		||||
				case "MygisMultiLineString": return MygisMultiLineString.Parse(string.Concat(value)) as MygisMultiLineString;
 | 
			
		||||
				case "MygisMultiPolygon": return MygisMultiPolygon.Parse(string.Concat(value)) as MygisMultiPolygon;
 | 
			
		||||
				case "Newtonsoft.Json.Linq.JToken": return JToken.Parse(string.Concat(value));
 | 
			
		||||
				case "Newtonsoft.Json.Linq.JObject": return JObject.Parse(string.Concat(value));
 | 
			
		||||
				case "Newtonsoft.Json.Linq.JArray": return JArray.Parse(string.Concat(value));
 | 
			
		||||
				case "Npgsql.LegacyPostgis.PostgisGeometry": return value;
 | 
			
		||||
			}
 | 
			
		||||
			if (type != value.GetType()) {
 | 
			
		||||
				if (type.FullName == "System.TimeSpan") return TimeSpan.FromSeconds(double.Parse(value.ToString()));
 | 
			
		||||
				return Convert.ChangeType(value, type);
 | 
			
		||||
			}
 | 
			
		||||
			return value;
 | 
			
		||||
		}
 | 
			
		||||
		internal static string GetCsName(string name) {
 | 
			
		||||
		public static string GetCsName(string name) {
 | 
			
		||||
			name = Regex.Replace(name.TrimStart('@'), @"[^\w]", "_");
 | 
			
		||||
			return char.IsLetter(name, 0) ? name : string.Concat("_", name);
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user