using FreeSql.Internal.Model; using FreeSql.Internal.ObjectPool; using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; #if net40 #else namespace FreeSql.Internal.CommonProvider { partial class AdoProvider { async public Task ExecuteConnectTestAsync(int commandTimeout = 0, CancellationToken cancellationToken = default) { try { switch (DataType) { case DataType.Oracle: case DataType.OdbcOracle: await ExecuteNonQueryAsync(null, null, CommandType.Text, " SELECT 1 FROM dual", commandTimeout, null, cancellationToken); return true; case DataType.Firebird: await ExecuteNonQueryAsync(null, null, CommandType.Text, " SELECT FIRST 1 1 FROM rdb$database", commandTimeout, null, cancellationToken); return true; } await ExecuteNonQueryAsync(null, null, CommandType.Text, " SELECT 1", commandTimeout, null, cancellationToken); return true; } catch { return false; } } async public Task QuerySingleAsync(string cmdText, object parms = null, CancellationToken cancellationToken = default) => (await QueryAsync(cmdText, parms, cancellationToken)).FirstOrDefault(); async public Task QuerySingleAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => (await QueryAsync(cmdType, cmdText, cmdParms, cancellationToken)).FirstOrDefault(); public Task> QueryAsync(string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(null, null, null, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task> QueryAsync(DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(null, null, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task> QueryAsync(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(null, connection, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task> QueryAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => QueryAsync(null, null, null, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task> QueryAsync(DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => QueryAsync(null, null, transaction, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task> QueryAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => QueryAsync(null, connection, transaction, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken); async public Task> QueryAsync(Type resultType, DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) { var ret = new List(); if (string.IsNullOrEmpty(cmdText)) return ret; var type = typeof(T); if (resultType != null && type != resultType) type = resultType; string flag = null; int[] indexes = null; var props = GetQueryTypeProperties(type); await ExecuteReaderAsync(connection, transaction, fetch => { if (indexes == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes = props.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag = sbflag.ToString(); } ret.Add((T)Utils.ExecuteArrayRowReadClassOrTuple(flag, type, indexes, fetch.Object, 0, _util).Value); return Task.FromResult(false); }, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken); return ret; } #region QueryAsync multi public Task, List>> QueryAsync(string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(null, null, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List>> QueryAsync(DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(null, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List>> QueryAsync(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(connection, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List>> QueryAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => QueryAsync(null, null, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task, List>> QueryAsync(DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => QueryAsync(null, transaction, cmdType, cmdText, 0, cmdParms, cancellationToken); async public Task, List>> QueryAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(cmdText)) return NativeTuple.Create(new List(), new List()); var ret1 = new List(); var type1 = typeof(T1); string flag1 = null; int[] indexes1 = null; var props1 = GetQueryTypeProperties(type1); var ret2 = new List(); var type2 = typeof(T2); string flag2 = null; int[] indexes2 = null; var props2 = GetQueryTypeProperties(type2); await ExecuteReaderMultipleAsync(2, connection, transaction, (fetch, result) => { switch (result) { case 0: if (indexes1 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes1 = props1.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag1 = sbflag.ToString(); } ret1.Add((T1)Utils.ExecuteArrayRowReadClassOrTuple(flag1, type1, indexes1, fetch.Object, 0, _util).Value); break; case 1: if (indexes2 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes2 = props2.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag2 = sbflag.ToString(); } ret2.Add((T2)Utils.ExecuteArrayRowReadClassOrTuple(flag2, type2, indexes2, fetch.Object, 0, _util).Value); break; } return Task.FromResult(false); }, null, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken); return NativeTuple.Create(ret1, ret2); } public Task, List, List>> QueryAsync(string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(null, null, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List, List>> QueryAsync(DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(null, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List, List>> QueryAsync(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(connection, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List, List>> QueryAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => QueryAsync(null, null, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task, List, List>> QueryAsync(DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => QueryAsync(null, transaction, cmdType, cmdText, 0, cmdParms, cancellationToken); async public Task, List, List>> QueryAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(cmdText)) return NativeTuple.Create(new List(), new List(), new List()); var ret1 = new List(); var type1 = typeof(T1); string flag1 = null; int[] indexes1 = null; var props1 = GetQueryTypeProperties(type1); var ret2 = new List(); var type2 = typeof(T2); string flag2 = null; int[] indexes2 = null; var props2 = GetQueryTypeProperties(type2); var ret3 = new List(); var type3 = typeof(T3); string flag3 = null; int[] indexes3 = null; var props3 = GetQueryTypeProperties(type3); await ExecuteReaderMultipleAsync(3, connection, transaction, (fetch, result) => { switch (result) { case 0: if (indexes1 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes1 = props1.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag1 = sbflag.ToString(); } ret1.Add((T1)Utils.ExecuteArrayRowReadClassOrTuple(flag1, type1, indexes1, fetch.Object, 0, _util).Value); break; case 1: if (indexes2 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes2 = props2.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag2 = sbflag.ToString(); } ret2.Add((T2)Utils.ExecuteArrayRowReadClassOrTuple(flag2, type2, indexes2, fetch.Object, 0, _util).Value); break; case 2: if (indexes3 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes3 = props3.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag3 = sbflag.ToString(); } ret3.Add((T3)Utils.ExecuteArrayRowReadClassOrTuple(flag3, type3, indexes3, fetch.Object, 0, _util).Value); break; } return Task.FromResult(false); }, null, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken); return NativeTuple.Create(ret1, ret2, ret3); } public Task, List, List, List>> QueryAsync(string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(null, null, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List, List, List>> QueryAsync(DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(null, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List, List, List>> QueryAsync(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(connection, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List, List, List>> QueryAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => QueryAsync(null, null, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task, List, List, List>> QueryAsync(DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => QueryAsync(null, transaction, cmdType, cmdText, 0, cmdParms, cancellationToken); async public Task, List, List, List>> QueryAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(cmdText)) return NativeTuple.Create(new List(), new List(), new List(), new List()); var ret1 = new List(); var type1 = typeof(T1); string flag1 = null; int[] indexes1 = null; var props1 = GetQueryTypeProperties(type1); var ret2 = new List(); var type2 = typeof(T2); string flag2 = null; int[] indexes2 = null; var props2 = GetQueryTypeProperties(type2); var ret3 = new List(); var type3 = typeof(T3); string flag3 = null; int[] indexes3 = null; var props3 = GetQueryTypeProperties(type3); var ret4 = new List(); var type4 = typeof(T4); string flag4 = null; int[] indexes4 = null; var props4 = GetQueryTypeProperties(type4); await ExecuteReaderMultipleAsync(4, connection, transaction, (fetch, result) => { switch (result) { case 0: if (indexes1 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes1 = props1.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag1 = sbflag.ToString(); } ret1.Add((T1)Utils.ExecuteArrayRowReadClassOrTuple(flag1, type1, indexes1, fetch.Object, 0, _util).Value); break; case 1: if (indexes2 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes2 = props2.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag2 = sbflag.ToString(); } ret2.Add((T2)Utils.ExecuteArrayRowReadClassOrTuple(flag2, type2, indexes2, fetch.Object, 0, _util).Value); break; case 2: if (indexes3 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes3 = props3.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag3 = sbflag.ToString(); } ret3.Add((T3)Utils.ExecuteArrayRowReadClassOrTuple(flag3, type3, indexes3, fetch.Object, 0, _util).Value); break; case 3: if (indexes4 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes4 = props4.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag4 = sbflag.ToString(); } ret4.Add((T4)Utils.ExecuteArrayRowReadClassOrTuple(flag4, type4, indexes4, fetch.Object, 0, _util).Value); break; } return Task.FromResult(false); }, null, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken); return NativeTuple.Create(ret1, ret2, ret3, ret4); } public Task, List, List, List, List>> QueryAsync(string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(null, null, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List, List, List, List>> QueryAsync(DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(null, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List, List, List, List>> QueryAsync(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync(connection, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task, List, List, List, List>> QueryAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => QueryAsync(null, null, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task, List, List, List, List>> QueryAsync(DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => QueryAsync(null, transaction, cmdType, cmdText, 0, cmdParms, cancellationToken); async public Task, List, List, List, List>> QueryAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(cmdText)) return NativeTuple.Create(new List(), new List(), new List(), new List(), new List()); var ret1 = new List(); var type1 = typeof(T1); string flag1 = null; int[] indexes1 = null; var props1 = GetQueryTypeProperties(type1); var ret2 = new List(); var type2 = typeof(T2); string flag2 = null; int[] indexes2 = null; var props2 = GetQueryTypeProperties(type2); var ret3 = new List(); var type3 = typeof(T3); string flag3 = null; int[] indexes3 = null; var props3 = GetQueryTypeProperties(type3); var ret4 = new List(); var type4 = typeof(T4); string flag4 = null; int[] indexes4 = null; var props4 = GetQueryTypeProperties(type4); var ret5 = new List(); var type5 = typeof(T5); string flag5 = null; int[] indexes5 = null; var props5 = GetQueryTypeProperties(type5); await ExecuteReaderMultipleAsync(5, connection, transaction, (fetch, result) => { switch (result) { case 0: if (indexes1 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes1 = props1.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag1 = sbflag.ToString(); } ret1.Add((T1)Utils.ExecuteArrayRowReadClassOrTuple(flag1, type1, indexes1, fetch.Object, 0, _util).Value); break; case 1: if (indexes2 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes2 = props2.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag2 = sbflag.ToString(); } ret2.Add((T2)Utils.ExecuteArrayRowReadClassOrTuple(flag2, type2, indexes2, fetch.Object, 0, _util).Value); break; case 2: if (indexes3 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes3 = props3.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag3 = sbflag.ToString(); } ret3.Add((T3)Utils.ExecuteArrayRowReadClassOrTuple(flag3, type3, indexes3, fetch.Object, 0, _util).Value); break; case 3: if (indexes4 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes4 = props4.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag4 = sbflag.ToString(); } ret4.Add((T4)Utils.ExecuteArrayRowReadClassOrTuple(flag4, type4, indexes4, fetch.Object, 0, _util).Value); break; case 4: if (indexes5 == null) { var sbflag = new StringBuilder().Append("adoQuery"); var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase); for (var a = 0; a < fetch.Object.FieldCount; a++) { var name = fetch.Object.GetName(a); if (dic.ContainsKey(name)) continue; sbflag.Append(name).Append(":").Append(a).Append(","); dic.Add(name, a); } indexes5 = props5.Select(a => dic.TryGetValue(a.Key, out var tryint) ? tryint : -1).ToArray(); flag5 = sbflag.ToString(); } ret5.Add((T5)Utils.ExecuteArrayRowReadClassOrTuple(flag5, type5, indexes5, fetch.Object, 0, _util).Value); break; } return Task.FromResult(false); }, null, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken); return NativeTuple.Create(ret1, ret2, ret3, ret4, ret5); } #endregion public Task ExecuteReaderAsync(Func, Task> fetchHandler, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteReaderAsync(null, null, fetchHandler, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteReaderAsync(DbTransaction transaction, Func, Task> fetchHandler, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteReaderAsync(null, transaction, fetchHandler, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteReaderAsync(DbConnection connection, DbTransaction transaction, Func, Task> fetchHandler, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteReaderAsync(connection, transaction, fetchHandler, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteReaderAsync(Func, Task> fetchHandler, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteReaderAsync(null, null, fetchHandler, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task ExecuteReaderAsync(DbTransaction transaction, Func, Task> fetchHandler, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteReaderAsync(null, transaction, fetchHandler, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task ExecuteReaderAsync(DbConnection connection, DbTransaction transaction, Func, Task> fetchHandler, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteReaderMultipleAsync(1, connection, transaction, (fetch, result) => fetchHandler(fetch), null, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken); async Task ExecuteReaderMultipleAsync(int multipleResult, DbConnection connection, DbTransaction transaction, Func, int, Task> fetchHandler, Action schemaHandler, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(cmdText)) return; var dt = DateTime.Now; var logtxt = new StringBuilder(); var logtxt_dt = DateTime.Now; var pool = this.MasterPool; var isSlave = false; if (transaction == null && connection == null) { //读写分离规则 if (this.SlavePools.Any() && IsFromSlave(cmdText)) { var availables = slaveUnavailables == 0 ? //查从库 this.SlavePools : ( //查主库 slaveUnavailables == this.SlavePools.Count ? new List>() : //查从库可用 this.SlavePools.Where(sp => sp.IsAvailable).ToList()); if (availables.Any()) { isSlave = true; pool = availables.Count == 1 ? this.SlavePools[0] : availables[slaveRandom.Next(availables.Count)]; } } } Object conn = null; var pc = await PrepareCommandAsync(connection, transaction, cmdType, cmdText, cmdTimeout, cmdParms, logtxt, cancellationToken); if (IsTracePerformance) { logtxt.Append("PrepareCommand: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); logtxt_dt = DateTime.Now; } Exception ex = null; try { if (isSlave) { //从库查询切换,恢复 bool isSlaveFail = false; try { if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = await pool.GetAsync()).Value; //if (slaveRandom.Next(100) % 2 == 0) throw new Exception("测试从库抛出异常"); } catch { isSlaveFail = true; } if (isSlaveFail) { if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(pool, conn, ex); //pool.Return(conn, ex); if (IsTracePerformance) logtxt.Append("Pool.Return: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(pool, pc, new Exception($"连接失败,准备切换其他可用服务器"), dt, logtxt, false); pc.cmd.Parameters.Clear(); if (DataType == DataType.Sqlite) pc.cmd.Dispose(); await ExecuteReaderMultipleAsync(multipleResult, connection, transaction, fetchHandler, schemaHandler, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken); return; } } else { //主库查询 if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = await pool.GetAsync()).Value; } if (IsTracePerformance) { logtxt.Append("Pool.Get: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); logtxt_dt = DateTime.Now; } using (var dr = await pc.cmd.ExecuteReaderAsync(cancellationToken)) { int resultIndex = 0; var fetch = new FetchCallbackArgs { Object = dr }; while (true) { bool isfirst = true; while (true) { bool isread = await dr.ReadAsync(cancellationToken); if (schemaHandler != null && isfirst) { isfirst = false; schemaHandler(dr, resultIndex); } if (isread == false) break; if (fetchHandler != null) { await fetchHandler(fetch, resultIndex); if (fetch.IsBreak) { resultIndex = multipleResult; break; } } } if (++resultIndex >= multipleResult || dr.NextResult() == false) break; } dr.Close(); } if (IsTracePerformance) { logtxt.Append("ExecuteReader: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); logtxt_dt = DateTime.Now; } } catch (Exception ex2) { ex = ex2; } if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(pool, conn, ex); //pool.Return(conn, ex); if (IsTracePerformance) logtxt.Append("Pool.Return: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(pool, pc, ex, dt, logtxt); pc.cmd.Parameters.Clear(); if (DataType == DataType.Sqlite) pc.cmd.Dispose(); } public Task ExecuteArrayAsync(string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteArrayAsync(null, null, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteArrayAsync(DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteArrayAsync(null, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteArrayAsync(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteArrayAsync(connection, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteArrayAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteArrayAsync(null, null, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task ExecuteArrayAsync(DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteArrayAsync(null, transaction, cmdType, cmdText, 0, cmdParms, cancellationToken); async public Task ExecuteArrayAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) { List ret = new List(); await ExecuteReaderAsync(connection, transaction, async fetch => { object[] values = new object[fetch.Object.FieldCount]; for (int a = 0; a < values.Length; a++) if (!await fetch.Object.IsDBNullAsync(a, cancellationToken)) values[a] = await fetch.Object.GetFieldValueAsync(a, cancellationToken); ret.Add(values); }, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken); return ret.ToArray(); } public Task ExecuteDataSetAsync(string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteDataSetAsync(null, null, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteDataSetAsync(DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteDataSetAsync(null, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteDataSetAsync(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteDataSetAsync(connection, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteDataSetAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteDataSetAsync(null, null, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task ExecuteDataSetAsync(DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteDataSetAsync(null, transaction, cmdType, cmdText, 0, cmdParms, cancellationToken); async public Task ExecuteDataSetAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) { var ret = new DataSet(); DataTable dt = null; await ExecuteReaderMultipleAsync(16, connection, transaction, async (fetch, result) => { object[] values = new object[dt.Columns.Count]; for (int a = 0; a < values.Length; a++) if (!await fetch.Object.IsDBNullAsync(a, cancellationToken)) values[a] = await fetch.Object.GetFieldValueAsync(a, cancellationToken); dt.Rows.Add(values); }, (dr, result) => { dt = ret.Tables.Add(); for (var a = 0; a < dr.FieldCount; a++) { var name = dr.GetName(a); if (dt.Columns.Contains(name)) name = $"{name}_{Guid.NewGuid().ToString("N").Substring(0, 4)}"; dt.Columns.Add(name, dr.GetFieldType(a)); } }, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken); return ret; } public Task ExecuteDataTableAsync(string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteDataTableAsync(null, null, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteDataTableAsync(DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteDataTableAsync(null, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteDataTableAsync(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteDataTableAsync(connection, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteDataTableAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteDataTableAsync(null, null, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task ExecuteDataTableAsync(DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteDataTableAsync(null, transaction, cmdType, cmdText, 0, cmdParms, cancellationToken); async public Task ExecuteDataTableAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) { var ret = new DataTable(); await ExecuteReaderMultipleAsync(1, connection, transaction, async (fetch, result) => { object[] values = new object[ret.Columns.Count]; for (int a = 0; a < values.Length; a++) if (!await fetch.Object.IsDBNullAsync(a, cancellationToken)) values[a] = await fetch.Object.GetFieldValueAsync(a, cancellationToken); ret.Rows.Add(values); }, (dr, result) => { for (var a = 0; a < dr.FieldCount; a++) { var name = dr.GetName(a); if (ret.Columns.Contains(name)) name = $"{name}_{Guid.NewGuid().ToString("N").Substring(0, 4)}"; ret.Columns.Add(name, dr.GetFieldType(a)); } }, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken); return ret; } public Task ExecuteNonQueryAsync(string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteNonQueryAsync(null, null, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteNonQueryAsync(DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteNonQueryAsync(null, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteNonQueryAsync(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteNonQueryAsync(connection, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteNonQueryAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteNonQueryAsync(null, null, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task ExecuteNonQueryAsync(DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteNonQueryAsync(null, transaction, cmdType, cmdText, 0, cmdParms, cancellationToken); async public Task ExecuteNonQueryAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(cmdText)) return 0; var dt = DateTime.Now; var logtxt = new StringBuilder(); var logtxt_dt = DateTime.Now; Object conn = null; var pc = await PrepareCommandAsync(connection, transaction, cmdType, cmdText, cmdTimeout, cmdParms, logtxt, cancellationToken); int val = 0; Exception ex = null; try { if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = await this.MasterPool.GetAsync()).Value; val = await pc.cmd.ExecuteNonQueryAsync(cancellationToken); } catch (Exception ex2) { ex = ex2; } if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex); if (IsTracePerformance) logtxt.Append("Pool.Return: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(this.MasterPool, pc, ex, dt, logtxt); pc.cmd.Parameters.Clear(); if (DataType == DataType.Sqlite) pc.cmd.Dispose(); return val; } public Task ExecuteScalarAsync(string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteScalarAsync(null, null, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteScalarAsync(DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteScalarAsync(null, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteScalarAsync(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteScalarAsync(connection, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken); public Task ExecuteScalarAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteScalarAsync(null, null, cmdType, cmdText, 0, cmdParms, cancellationToken); public Task ExecuteScalarAsync(DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteScalarAsync(null, transaction, cmdType, cmdText, 0, cmdParms, cancellationToken); async public Task ExecuteScalarAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(cmdText)) return null; var dt = DateTime.Now; var logtxt = new StringBuilder(); var logtxt_dt = DateTime.Now; Object conn = null; var pc = await PrepareCommandAsync(connection, transaction, cmdType, cmdText, cmdTimeout, cmdParms, logtxt, cancellationToken); object val = null; Exception ex = null; try { if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = await this.MasterPool.GetAsync()).Value; val = await pc.cmd.ExecuteScalarAsync(cancellationToken); } catch (Exception ex2) { ex = ex2; } if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex); if (IsTracePerformance) logtxt.Append("Pool.Return: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(this.MasterPool, pc, ex, dt, logtxt); pc.cmd.Parameters.Clear(); if (DataType == DataType.Sqlite) pc.cmd.Dispose(); return val; } async Task PrepareCommandAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, StringBuilder logtxt, CancellationToken cancellationToken = default) { DateTime dt = DateTime.Now; DbCommand cmd = CreateCommand(); bool isclose = false; cmd.CommandType = cmdType; cmd.CommandText = cmdText; if (cmdTimeout > 0) cmd.CommandTimeout = cmdTimeout; if (cmdParms != null) { foreach (var parm in cmdParms) { if (parm == null) continue; var isnew = false; if (parm.Value == null) parm.Value = DBNull.Value; else { if (parm.Value is Array || parm.Value is IList) { cmd.CommandText = Regex.Replace(cmd.CommandText, @"\s+(in|In|IN|iN)\s+[\:\?\@]" + parm.ParameterName.TrimStart('@', '?', ':'), m => { isnew = true; var arr = parm.Value as IEnumerable; if (arr == null) return " IS NULL"; var vals = new List(); foreach (var val in arr) vals.Add(val); return $" in {_util.FormatSql("{0}", new object[] { vals })}"; }); } } if (isnew == false) cmd.Parameters.Add(parm); } } if (connection == null) { var tran = transaction ?? ResolveTransaction?.Invoke(); if (tran != null) { cmd.Connection = tran.Connection; cmd.Transaction = tran; } } else { if (connection.State != ConnectionState.Open) { if (IsTracePerformance) dt = DateTime.Now; await connection.OpenAsync(cancellationToken); if (IsTracePerformance) logtxt.Append(" PrepareCommand_ConnectionOpen: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); isclose = true; } cmd.Connection = connection; if (transaction?.Connection == connection) cmd.Transaction = transaction; } var before = new Aop.CommandBeforeEventArgs(cmd); _util?._orm?.Aop.CommandBeforeHandler?.Invoke(_util._orm, before); return new PrepareCommandResult(before, cmd, isclose); } } } #endif