using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace SqlSugar
{
///
/// ** description:ActiveX Data Objects
/// ** author:sunkaixuan
/// ** date:2017/1/2
/// ** email:610262374@qq.com
///
public abstract partial class AdoProvider : AdoAccessory, IAdo
{
#region Constructor
public AdoProvider()
{
this.IsEnableLogEvent = false;
this.CommandType = CommandType.Text;
this.IsClearParameters = true;
this.CommandTimeOut = 300;
}
#endregion
#region Properties
internal bool IsOpenAsync { get; set; }
protected List OutputParameters { get; set; }
public virtual string SqlParameterKeyWord { get { return "@"; } }
public IDbTransaction Transaction { get; set; }
public virtual SqlSugarProvider Context { get; set; }
internal CommandType OldCommandType { get; set; }
internal bool OldClearParameters { get; set; }
public IDataParameterCollection DataReaderParameters { get; set; }
public TimeSpan SqlExecutionTime { get { return AfterTime - BeforeTime; } }
public TimeSpan ConnectionExecutionTime { get { return CheckConnectionAfterTime - CheckConnectionBeforeTime; } }
public TimeSpan GetDataExecutionTime { get { return GetDataAfterTime - GetDataBeforeTime; } }
///
/// Add, delete and modify: the number of affected items;
///
public int SqlExecuteCount { get; private set; } = 0;
public StackTraceInfo SqlStackTrace { get { return UtilMethods.GetStackTrace(); } }
public bool IsDisableMasterSlaveSeparation { get; set; }
internal DateTime BeforeTime = DateTime.MinValue;
internal DateTime AfterTime = DateTime.MinValue;
internal DateTime GetDataBeforeTime = DateTime.MinValue;
internal DateTime GetDataAfterTime = DateTime.MinValue;
internal DateTime CheckConnectionBeforeTime = DateTime.MinValue;
internal DateTime CheckConnectionAfterTime = DateTime.MinValue;
public virtual IDbBind DbBind
{
get
{
if (base._DbBind == null)
{
IDbBind bind = InstanceFactory.GetDbBind(this.Context.CurrentConnectionConfig);
base._DbBind = bind;
bind.Context = this.Context;
}
return base._DbBind;
}
}
public virtual int CommandTimeOut { get; set; }
public virtual CommandType CommandType { get; set; }
public virtual bool IsEnableLogEvent { get; set; }
public virtual bool IsClearParameters { get; set; }
public virtual Action LogEventStarting => this.Context.CurrentConnectionConfig.AopEvents?.OnLogExecuting;
public virtual Action LogEventCompleted => this.Context.CurrentConnectionConfig.AopEvents?.OnLogExecuted;
public virtual Action CheckConnectionExecuting => this.Context.CurrentConnectionConfig.AopEvents?.CheckConnectionExecuting;
public virtual Action CheckConnectionExecuted => this.Context.CurrentConnectionConfig.AopEvents?.CheckConnectionExecuted;
public virtual Action OnGetDataReadering => this.Context.CurrentConnectionConfig.AopEvents?.OnGetDataReadering;
public virtual Action OnGetDataReadered => this.Context.CurrentConnectionConfig.AopEvents?.OnGetDataReadered;
public virtual Func> ProcessingEventStartingSQL => this.Context.CurrentConnectionConfig.AopEvents?.OnExecutingChangeSql;
protected virtual Func FormatSql { get; set; }
public virtual Action ErrorEvent => this.Context.CurrentConnectionConfig.AopEvents?.OnError;
public virtual Action DiffLogEvent => this.Context.CurrentConnectionConfig.AopEvents?.OnDiffLogEvent;
public virtual List SlaveConnections { get; set; }
public virtual IDbConnection MasterConnection { get; set; }
public virtual string MasterConnectionString { get; set; }
public virtual CancellationToken? CancellationToken { get; set; }
#endregion
#region Connection
public virtual bool IsValidConnection()
{
try
{
if (this.IsAnyTran())
{
return true;
}
using (OpenAlways())
{
return true;
}
}
catch (Exception)
{
return false;
}
}
public virtual bool IsValidConnectionNoClose()
{
try
{
this.Open();
return true;
}
catch (Exception)
{
return false;
}
}
public virtual void Open()
{
CheckConnection();
}
public virtual async Task OpenAsync()
{
await CheckConnectionAsync();
}
public SugarConnection OpenAlways()
{
SugarConnection result = new SugarConnection();
result.IsAutoClose = this.Context.CurrentConnectionConfig.IsAutoCloseConnection;
result.conn = this.Connection;
result.Context = this.Context;
this.Context.CurrentConnectionConfig.IsAutoCloseConnection = false;
this.Open();
return result;
}
public virtual void Close()
{
if (this.Transaction != null)
{
this.Transaction = null;
}
if (this.Connection != null && this.Connection.State == ConnectionState.Open)
{
this.Connection.Close();
}
if (this.IsMasterSlaveSeparation && this.SlaveConnections.HasValue())
{
foreach (var slaveConnection in this.SlaveConnections)
{
if (slaveConnection != null && slaveConnection.State == ConnectionState.Open)
{
slaveConnection.Close();
}
}
}
}
public virtual void Dispose()
{
if (this.Transaction != null)
{
this.Transaction.Rollback();
this.Transaction = null;
}
//if (this.Connection != null && this.Connection.State != ConnectionState.Open)
//{
// this.Connection.Close();
//}
if (this.Connection != null)
{
this.Connection.Dispose();
}
this.Connection = null;
if (this.IsMasterSlaveSeparation)
{
if (this.SlaveConnections != null)
{
foreach (var slaveConnection in this.SlaveConnections)
{
if (slaveConnection != null && slaveConnection.State == ConnectionState.Open)
{
slaveConnection.Dispose();
}
}
}
}
}
public virtual void CheckConnection()
{
this.CheckConnectionBefore(this.Connection);
if (this.Connection.State != ConnectionState.Open)
{
try
{
this.Connection.Open();
}
catch (Exception ex)
{
if (this.Context.CurrentConnectionConfig?.DbType==DbType.SqlServer&&ex.Message?.Contains("provider: SSL")==true)
{
Check.ExceptionEasy(true,ex.Message, "SSL出错,因为升级了驱动,字符串增加Encrypt=True;TrustServerCertificate=True;即可。详细错误:" + ex.Message);
}
Check.Exception(true, ErrorMessage.ConnnectionOpen, ex.Message+$"DbType=\"{this.Context.CurrentConnectionConfig.DbType}\";ConfigId=\"{this.Context.CurrentConnectionConfig.ConfigId}\"");
}
}
this.CheckConnectionAfter(this.Connection);
}
public virtual async Task CheckConnectionAsync()
{
this.CheckConnectionBefore(this.Connection);
if (this.Connection.State != ConnectionState.Open)
{
try
{
await (this.Connection as DbConnection).OpenAsync();
}
catch (Exception ex)
{
Check.Exception(true, ErrorMessage.ConnnectionOpen, ex.Message + $"DbType=\"{this.Context.CurrentConnectionConfig.DbType}\";ConfigId=\"{this.Context.CurrentConnectionConfig.ConfigId}\"");
}
}
this.CheckConnectionAfter(this.Connection);
}
public virtual void CheckConnectionBefore(IDbConnection Connection)
{
this.CheckConnectionBeforeTime = DateTime.Now;
if (this.IsEnableLogEvent)
{
Action action = CheckConnectionExecuting;
if (action != null)
{
action(Connection);
}
}
}
public virtual void CheckConnectionAfter(IDbConnection Connection)
{
this.CheckConnectionAfterTime = DateTime.Now;
if (this.IsEnableLogEvent)
{
Action action = CheckConnectionExecuted;
if (action != null)
{
action(Connection,this.ConnectionExecutionTime);
}
}
}
#endregion
#region Transaction
public virtual bool IsAnyTran()
{
return this.Transaction != null;
}
public virtual bool IsNoTran()
{
return this.Transaction == null;
}
public virtual void BeginTran()
{
CheckConnection();
if (this.Transaction == null)
this.Transaction = this.Connection.BeginTransaction();
}
public virtual async Task BeginTranAsync()
{
await CheckConnectionAsync();
if (this.Transaction == null)
this.Transaction =await (this.Connection as DbConnection).BeginTransactionAsync();
}
public virtual void BeginTran(IsolationLevel iso)
{
CheckConnection();
if (this.Transaction == null)
this.Transaction = this.Connection.BeginTransaction(iso);
}
public virtual async Task BeginTranAsync(IsolationLevel iso)
{
await CheckConnectionAsync();
if (this.Transaction == null)
this.Transaction =await (this.Connection as DbConnection).BeginTransactionAsync(iso);
}
public virtual void RollbackTran()
{
if (this.Transaction != null)
{
this.Transaction.Rollback();
this.Transaction = null;
if (this.Context.CurrentConnectionConfig.IsAutoCloseConnection) this.Close();
}
}
public virtual async Task RollbackTranAsync()
{
if (this.Transaction != null)
{
await (this.Transaction as DbTransaction).RollbackAsync();
this.Transaction = null;
if (this.Context.CurrentConnectionConfig.IsAutoCloseConnection) await this.CloseAsync();
}
}
public virtual void CommitTran()
{
if (this.Transaction != null)
{
this.Transaction.Commit();
this.Transaction = null;
if (this.Context.CurrentConnectionConfig.IsAutoCloseConnection) this.Close();
}
}
public virtual async Task CommitTranAsync()
{
if (this.Transaction != null)
{
await (this.Transaction as DbTransaction).CommitAsync();
this.Transaction = null;
if (this.Context.CurrentConnectionConfig.IsAutoCloseConnection) await this.CloseAsync();
}
}
#endregion
#region abstract
public abstract IDataParameter[] ToIDbDataParameter(params SugarParameter[] pars);
public abstract void SetCommandToAdapter(IDataAdapter adapter, DbCommand command);
public abstract IDataAdapter GetAdapter();
public abstract DbCommand GetCommand(string sql, SugarParameter[] pars);
public abstract IDbConnection Connection { get; set; }
public abstract void BeginTran(string transactionName);//Only SqlServer
public abstract void BeginTran(IsolationLevel iso, string transactionName);//Only SqlServer
#endregion
#region Use
public SqlSugarTransactionAdo UseTran()
{
return new SqlSugarTransactionAdo(this.Context);
}
public DbResult UseTran(Action action, Action errorCallBack = null)
{
var result = new DbResult();
try
{
this.BeginTran();
if (action != null)
action();
this.CommitTran();
result.Data = result.IsSuccess = true;
}
catch (Exception ex)
{
result.ErrorException = ex;
result.ErrorMessage = ex.Message;
result.IsSuccess = false;
this.RollbackTran();
if (errorCallBack != null)
{
errorCallBack(ex);
}
}
return result;
}
public async Task> UseTranAsync(Func action, Action errorCallBack = null)
{
var result = new DbResult();
try
{
await this.BeginTranAsync();
if (action != null)
await action();
await this.CommitTranAsync();
result.Data = result.IsSuccess = true;
}
catch (Exception ex)
{
result.ErrorException = ex;
result.ErrorMessage = ex.Message;
result.IsSuccess = false;
await this.RollbackTranAsync();
if (errorCallBack != null)
{
errorCallBack(ex);
}
}
return result;
}
public DbResult UseTran(Func action, Action errorCallBack = null)
{
var result = new DbResult();
try
{
this.BeginTran();
if (action != null)
result.Data = action();
this.CommitTran();
result.IsSuccess = true;
}
catch (Exception ex)
{
result.ErrorException = ex;
result.ErrorMessage = ex.Message;
result.IsSuccess = false;
this.RollbackTran();
if (errorCallBack != null)
{
errorCallBack(ex);
}
}
return result;
}
public async Task> UseTranAsync(Func> action, Action errorCallBack = null)
{
var result = new DbResult();
try
{
this.BeginTran();
if (action != null)
result.Data = await action();
this.CommitTran();
result.IsSuccess = true;
}
catch (Exception ex)
{
result.ErrorException = ex;
result.ErrorMessage = ex.Message;
result.IsSuccess = false;
this.RollbackTran();
if (errorCallBack != null)
{
errorCallBack(ex);
}
}
return result;
}
public IAdo UseStoredProcedure()
{
this.OldCommandType = this.CommandType;
this.OldClearParameters = this.IsClearParameters;
this.CommandType = CommandType.StoredProcedure;
this.IsClearParameters = false;
return this;
}
#endregion
#region Core
public virtual int ExecuteCommandWithGo(string sql, params SugarParameter[] parameters)
{
if (string.IsNullOrEmpty(sql))
return 0;
if (!sql.ToLower().Contains("go"))
{
return ExecuteCommand(sql);
}
System.Collections.ArrayList al = new System.Collections.ArrayList();
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(@"^(\s*)go(\s*)$", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline | System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.ExplicitCapture);
al.AddRange(reg.Split(sql));
int count = 0;
foreach (string item in al)
{
if (item.HasValue())
{
count += ExecuteCommand(item, parameters);
}
}
return count;
}
public virtual int ExecuteCommand(string sql, params SugarParameter[] parameters)
{
try
{
InitParameters(ref sql, parameters);
if (IsFormat(parameters))
sql = FormatSql(sql);
if (this.Context.CurrentConnectionConfig?.SqlMiddle?.IsSqlMiddle == true)
return this.Context.CurrentConnectionConfig.SqlMiddle.ExecuteCommand(sql, parameters);
SetConnectionStart(sql);
if (this.ProcessingEventStartingSQL != null)
ExecuteProcessingSQL(ref sql, ref parameters);
ExecuteBefore(sql, parameters);
IDbCommand sqlCommand = GetCommand(sql, parameters);
int count = sqlCommand.ExecuteNonQuery();
if (this.IsClearParameters)
sqlCommand.Parameters.Clear();
// 影响条数
this.SqlExecuteCount = count;
ExecuteAfter(sql, parameters);
sqlCommand.Dispose();
return count;
}
catch (Exception ex)
{
SugarCatch(ex, sql,parameters);
CommandType = CommandType.Text;
if (ErrorEvent != null)
ExecuteErrorEvent(sql, parameters, ex);
throw ex;
}
finally
{
if (this.IsAutoClose()) this.Close();
SetConnectionEnd(sql);
}
}
public virtual IDataReader GetDataReader(string sql, params SugarParameter[] parameters)
{
try
{
InitParameters(ref sql, parameters);
if (IsFormat(parameters))
sql = FormatSql(sql);
if (this.Context.CurrentConnectionConfig?.SqlMiddle?.IsSqlMiddle == true)
return this.Context.CurrentConnectionConfig.SqlMiddle.GetDataReader(sql, parameters);
SetConnectionStart(sql);
var isSp = this.CommandType == CommandType.StoredProcedure;
if (this.ProcessingEventStartingSQL != null)
ExecuteProcessingSQL(ref sql,ref parameters);
ExecuteBefore(sql, parameters);
IDbCommand sqlCommand = GetCommand(sql, parameters);
IDataReader sqlDataReader = sqlCommand.ExecuteReader(this.IsAutoClose() ? CommandBehavior.CloseConnection : CommandBehavior.Default);
if (isSp)
DataReaderParameters = sqlCommand.Parameters;
if (this.IsClearParameters)
sqlCommand.Parameters.Clear();
ExecuteAfter(sql, parameters);
SetConnectionEnd(sql);
if (SugarCompatible.IsFramework || this.Context.CurrentConnectionConfig.DbType != DbType.Sqlite)
sqlCommand.Dispose();
return sqlDataReader;
}
catch (Exception ex)
{
SugarCatch(ex, sql, parameters);
CommandType = CommandType.Text;
if (ErrorEvent != null)
ExecuteErrorEvent(sql, parameters, ex);
throw;
}
}
public virtual DataSet GetDataSetAll(string sql, params SugarParameter[] parameters)
{
try
{
InitParameters(ref sql, parameters);
if (IsFormat(parameters))
sql = FormatSql(sql);
if (this.Context.CurrentConnectionConfig?.SqlMiddle?.IsSqlMiddle == true)
return this.Context.CurrentConnectionConfig.SqlMiddle.GetDataSetAll(sql, parameters);
SetConnectionStart(sql);
if (this.ProcessingEventStartingSQL != null)
ExecuteProcessingSQL(ref sql,ref parameters);
ExecuteBefore(sql, parameters);
IDataAdapter dataAdapter = this.GetAdapter();
DbCommand sqlCommand = GetCommand(sql, parameters);
this.SetCommandToAdapter(dataAdapter, sqlCommand);
DataSet ds = new DataSet();
dataAdapter.Fill(ds);
if (this.IsClearParameters)
sqlCommand.Parameters.Clear();
ExecuteAfter(sql, parameters);
sqlCommand.Dispose();
return ds;
}
catch (Exception ex)
{
SugarCatch(ex, sql, parameters);
CommandType = CommandType.Text;
if (ErrorEvent != null)
ExecuteErrorEvent(sql, parameters, ex);
throw;
}
finally
{
if (this.IsAutoClose()) this.Close();
SetConnectionEnd(sql);
}
}
public virtual object GetScalar(string sql, params SugarParameter[] parameters)
{
try
{
InitParameters(ref sql, parameters);
if (IsFormat(parameters))
sql = FormatSql(sql);
if (this.Context.CurrentConnectionConfig?.SqlMiddle?.IsSqlMiddle == true)
return this.Context.CurrentConnectionConfig.SqlMiddle.GetScalar(sql, parameters);
SetConnectionStart(sql);
if (this.ProcessingEventStartingSQL != null)
ExecuteProcessingSQL(ref sql,ref parameters);
ExecuteBefore(sql, parameters);
IDbCommand sqlCommand = GetCommand(sql, parameters);
object scalar = sqlCommand.ExecuteScalar();
//scalar = (scalar == null ? 0 : scalar);
if (this.IsClearParameters)
sqlCommand.Parameters.Clear();
ExecuteAfter(sql, parameters);
sqlCommand.Dispose();
return scalar;
}
catch (Exception ex)
{
SugarCatch(ex, sql, parameters);
CommandType = CommandType.Text;
if (ErrorEvent != null)
ExecuteErrorEvent(sql, parameters, ex);
throw;
}
finally
{
if (this.IsAutoClose()) this.Close();
SetConnectionEnd(sql);
}
}
public virtual async Task ExecuteCommandAsync(string sql, params SugarParameter[] parameters)
{
try
{
Async();
InitParameters(ref sql, parameters);
if (IsFormat(parameters))
sql = FormatSql(sql);
if (this.Context.CurrentConnectionConfig?.SqlMiddle?.IsSqlMiddle == true)
return await this.Context.CurrentConnectionConfig.SqlMiddle.ExecuteCommandAsync(sql, parameters);
SetConnectionStart(sql);
if (this.ProcessingEventStartingSQL != null)
ExecuteProcessingSQL(ref sql,ref parameters);
ExecuteBefore(sql, parameters);
var sqlCommand =IsOpenAsync? await GetCommandAsync(sql, parameters) : GetCommand(sql, parameters);
int count;
if (this.CancellationToken == null)
count=await sqlCommand.ExecuteNonQueryAsync();
else
count=await sqlCommand.ExecuteNonQueryAsync(this.CancellationToken.Value);
if (this.IsClearParameters)
sqlCommand.Parameters.Clear();
this.SqlExecuteCount = count;
ExecuteAfter(sql, parameters);
sqlCommand.Dispose();
return count;
}
catch (Exception ex)
{
SugarCatch(ex, sql, parameters);
CommandType = CommandType.Text;
if (ErrorEvent != null)
ExecuteErrorEvent(sql, parameters, ex);
throw;
}
finally
{
if (this.IsAutoClose()) this.Close();
SetConnectionEnd(sql);
}
}
public virtual async Task GetDataReaderAsync(string sql, params SugarParameter[] parameters)
{
try
{
Async();
InitParameters(ref sql, parameters);
if (IsFormat(parameters))
sql = FormatSql(sql);
if (this.Context.CurrentConnectionConfig?.SqlMiddle?.IsSqlMiddle == true)
return await this.Context.CurrentConnectionConfig.SqlMiddle.GetDataReaderAsync(sql, parameters);
SetConnectionStart(sql);
var isSp = this.CommandType == CommandType.StoredProcedure;
if (this.ProcessingEventStartingSQL != null)
ExecuteProcessingSQL(ref sql,ref parameters);
ExecuteBefore(sql, parameters);
var sqlCommand = IsOpenAsync ? await GetCommandAsync(sql, parameters) : GetCommand(sql, parameters);
DbDataReader sqlDataReader;
if(this.CancellationToken==null)
sqlDataReader=await sqlCommand.ExecuteReaderAsync(this.IsAutoClose() ? CommandBehavior.CloseConnection : CommandBehavior.Default);
else
sqlDataReader=await sqlCommand.ExecuteReaderAsync(this.IsAutoClose() ? CommandBehavior.CloseConnection : CommandBehavior.Default,this.CancellationToken.Value);
if (isSp)
DataReaderParameters = sqlCommand.Parameters;
if (this.IsClearParameters)
sqlCommand.Parameters.Clear();
ExecuteAfter(sql, parameters);
SetConnectionEnd(sql);
if (SugarCompatible.IsFramework || this.Context.CurrentConnectionConfig.DbType != DbType.Sqlite)
sqlCommand.Dispose();
return sqlDataReader;
}
catch (Exception ex)
{
SugarCatch(ex, sql, parameters);
CommandType = CommandType.Text;
if (ErrorEvent != null)
ExecuteErrorEvent(sql, parameters, ex);
throw;
}
}
public virtual async Task