using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
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
protected AdoProvider()
{
this.IsEnableLogEvent = false;
this.CommandType = CommandType.Text;
this.IsClearParameters = true;
this.CommandTimeOut = 30000;
}
#endregion Constructor
#region Properties
protected List OutputParameters { get; set; }
public virtual string SqlParameterKeyWord { get { return "@"; } }
public IDbTransaction Transaction { get; set; }
public virtual SqlSugarClient Context { get; set; }
internal CommandType OldCommandType { get; set; }
internal bool OldClearParameters { get; set; }
public IDataParameterCollection DataReaderParameters { get; set; }
public virtual IDbBind DbBind
{
get
{
if (base._DbBind == null)
{
var 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 { get; set; }
public virtual Action LogEventCompleted { get; set; }
public virtual Func> ProcessingEventStartingSQL { get; set; }
protected virtual Func FormatSql { get; set; }
public virtual Action ErrorEvent { get; set; }
public virtual List SlaveConnections { get; set; }
public virtual IDbConnection MasterConnection { get; set; }
#endregion Properties
#region Connection
public virtual void Open()
{
CheckConnection();
}
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.Commit();
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)
{
foreach (var slaveConnection in this.SlaveConnections)
{
if (slaveConnection != null && slaveConnection.State == ConnectionState.Open)
{
slaveConnection.Dispose();
}
}
}
}
public virtual void CheckConnection()
{
if (this.Connection.State != ConnectionState.Open)
{
try
{
this.Connection.Open();
}
catch (Exception ex)
{
Check.Exception(true, ErrorMessage.ConnnectionOpen, ex.Message);
}
}
}
#endregion Connection
#region Transaction
public virtual void BeginTran()
{
CheckConnection();
this.Transaction = this.Connection.BeginTransaction();
}
public virtual void BeginTran(IsolationLevel iso)
{
CheckConnection();
this.Transaction = this.Connection.BeginTransaction(iso);
}
public virtual void RollbackTran()
{
if (this.Transaction != null)
{
this.Transaction.Rollback();
this.Transaction = null;
if (this.Context.CurrentConnectionConfig.IsAutoCloseConnection) this.Close();
}
}
public virtual void CommitTran()
{
if (this.Transaction != null)
{
this.Transaction.Commit();
this.Transaction = null;
if (this.Context.CurrentConnectionConfig.IsAutoCloseConnection) this.Close();
}
}
#endregion Transaction
#region abstract
public abstract IDataParameter[] ToIDbDataParameter(params SugarParameter[] pars);
public abstract void SetCommandToAdapter(IDataAdapter adapter, IDbCommand command);
public abstract IDataAdapter GetAdapter();
public abstract IDbCommand 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 abstract
#region Use
public DbResult UseTran(Action action)
{
var result = new DbResult();
try
{
this.BeginTran();
action?.Invoke();
this.CommitTran();
result.Data = result.IsSuccess = true;
}
catch (Exception ex)
{
result.ErrorException = ex;
result.ErrorMessage = ex.Message;
result.IsSuccess = false;
this.RollbackTran();
}
return result;
}
public DbResult UseTran(Func action)
{
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();
}
return result;
}
public void UseStoredProcedure(Action action)
{
var oldCommandType = this.CommandType;
this.CommandType = CommandType.StoredProcedure;
this.IsClearParameters = false;
action?.Invoke();
this.CommandType = oldCommandType;
this.IsClearParameters = true;
}
public T UseStoredProcedure(Func action)
{
var result = default(T);
var oldCommandType = this.CommandType;
this.CommandType = CommandType.StoredProcedure;
this.IsClearParameters = false;
if (action != null)
{
result = action();
}
this.CommandType = oldCommandType;
this.IsClearParameters = true;
return result;
}
public IAdo UseStoredProcedure()
{
this.OldCommandType = this.CommandType;
this.OldClearParameters = this.IsClearParameters;
this.CommandType = CommandType.StoredProcedure;
this.IsClearParameters = false;
return this;
}
#endregion Use
#region Core
public virtual int ExecuteCommand(string sql, params SugarParameter[] parameters)
{
try
{
if (FormatSql != null)
sql = FormatSql(sql);
SetConnectionStart(sql);
if (this.ProcessingEventStartingSQL != null)
ExecuteProcessingSQL(ref sql, parameters);
ExecuteBefore(sql, parameters);
var sqlCommand = GetCommand(sql, parameters);
var count = sqlCommand.ExecuteNonQuery();
if (this.IsClearParameters)
sqlCommand.Parameters.Clear();
ExecuteAfter(sql, parameters);
return count;
}
catch (Exception ex)
{
ErrorEvent?.Invoke(ex);
throw ex;
}
finally
{
if (this.IsAutoClose()) this.Close();
SetConnectionEnd(sql);
}
}
public virtual IDataReader GetDataReader(string sql, params SugarParameter[] parameters)
{
try
{
if (FormatSql != null)
sql = FormatSql(sql);
SetConnectionStart(sql);
var isSp = this.CommandType == CommandType.StoredProcedure;
if (this.ProcessingEventStartingSQL != null)
ExecuteProcessingSQL(ref sql, parameters);
ExecuteBefore(sql, parameters);
var sqlCommand = GetCommand(sql, parameters);
var 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);
return sqlDataReader;
}
catch (Exception ex)
{
ErrorEvent?.Invoke(ex);
throw ex;
}
}
public virtual DataSet GetDataSetAll(string sql, params SugarParameter[] parameters)
{
try
{
if (FormatSql != null)
sql = FormatSql(sql);
SetConnectionStart(sql);
if (this.ProcessingEventStartingSQL != null)
ExecuteProcessingSQL(ref sql, parameters);
ExecuteBefore(sql, parameters);
var dataAdapter = this.GetAdapter();
var sqlCommand = GetCommand(sql, parameters);
this.SetCommandToAdapter(dataAdapter, sqlCommand);
var ds = new DataSet();
dataAdapter.Fill(ds);
if (this.IsClearParameters)
sqlCommand.Parameters.Clear();
ExecuteAfter(sql, parameters);
return ds;
}
catch (Exception ex)
{
ErrorEvent?.Invoke(ex);
throw ex;
}
finally
{
if (this.IsAutoClose()) this.Close();
SetConnectionEnd(sql);
}
}
public virtual object GetScalar(string sql, params SugarParameter[] parameters)
{
try
{
if (FormatSql != null)
sql = FormatSql(sql);
SetConnectionStart(sql);
if (this.ProcessingEventStartingSQL != null)
ExecuteProcessingSQL(ref sql, parameters);
ExecuteBefore(sql, parameters);
var sqlCommand = GetCommand(sql, parameters);
var scalar = sqlCommand.ExecuteScalar();
//scalar = (scalar == null ? 0 : scalar);
if (this.IsClearParameters)
sqlCommand.Parameters.Clear();
ExecuteAfter(sql, parameters);
return scalar;
}
catch (Exception ex)
{
ErrorEvent?.Invoke(ex);
throw ex;
}
finally
{
if (this.IsAutoClose()) this.Close();
SetConnectionEnd(sql);
}
}
#endregion Core
#region Methods
public virtual string GetString(string sql, object parameters)
{
return GetString(sql, this.GetParameters(parameters));
}
public virtual string GetString(string sql, params SugarParameter[] parameters)
{
return Convert.ToString(GetScalar(sql, parameters));
}
public virtual string GetString(string sql, List parameters)
{
return parameters == null ? GetString(sql) : GetString(sql, parameters.ToArray());
}
public virtual int GetInt(string sql, object parameters)
{
return GetInt(sql, this.GetParameters(parameters));
}
public virtual int GetInt(string sql, params SugarParameter[] parameters)
{
return GetScalar(sql, parameters).ObjToInt();
}
public virtual int GetInt(string sql, List parameters)
{
return parameters == null ? GetInt(sql) : GetInt(sql, parameters.ToArray());
}
public virtual Double GetDouble(string sql, object parameters)
{
return GetDouble(sql, this.GetParameters(parameters));
}
public virtual Double GetDouble(string sql, params SugarParameter[] parameters)
{
return GetScalar(sql, parameters).ObjToMoney();
}
public virtual Double GetDouble(string sql, List parameters)
{
return parameters == null ? GetDouble(sql) : GetDouble(sql, parameters.ToArray());
}
public virtual decimal GetDecimal(string sql, object parameters)
{
return GetDecimal(sql, this.GetParameters(parameters));
}
public virtual decimal GetDecimal(string sql, params SugarParameter[] parameters)
{
return GetScalar(sql, parameters).ObjToDecimal();
}
public virtual decimal GetDecimal(string sql, List parameters)
{
return parameters == null ? GetDecimal(sql) : GetDecimal(sql, parameters.ToArray());
}
public virtual DateTime GetDateTime(string sql, object parameters)
{
return GetDateTime(sql, this.GetParameters(parameters));
}
public virtual DateTime GetDateTime(string sql, params SugarParameter[] parameters)
{
return GetScalar(sql, parameters).ObjToDate();
}
public virtual DateTime GetDateTime(string sql, List parameters)
{
return parameters == null ? GetDateTime(sql) : GetDateTime(sql, parameters.ToArray());
}
public virtual List SqlQuery(string sql, object parameters = null)
{
var sugarParameters = this.GetParameters(parameters);
return SqlQuery(sql, sugarParameters);
}
public virtual List SqlQuery(string sql, params SugarParameter[] parameters)
{
this.Context.InitMppingInfo();
var builder = InstanceFactory.GetSqlbuilder(this.Context.CurrentConnectionConfig);
builder.SqlQueryBuilder.sql.Append(sql);
if (parameters != null && parameters.Any())
builder.SqlQueryBuilder.Parameters.AddRange(parameters);
var dataReader = this.GetDataReader(builder.SqlQueryBuilder.ToSqlString(), builder.SqlQueryBuilder.Parameters.ToArray());
var result = this.DbBind.DataReaderToList(typeof(T), dataReader);
builder.SqlQueryBuilder.Clear();
if (this.Context.Ado.DataReaderParameters != null)
{
foreach (IDataParameter item in this.Context.Ado.DataReaderParameters)
{
var parameter = parameters.FirstOrDefault(it => item.ParameterName.Substring(1) == it.ParameterName.Substring(1));
if (parameter != null)
{
parameter.Value = item.Value;
}
}
this.Context.Ado.DataReaderParameters = null;
}
return result;
}
public virtual List SqlQuery(string sql, List parameters)
{
return parameters != null ? SqlQuery(sql, parameters.ToArray()) : SqlQuery(sql);
}
public virtual T SqlQuerySingle(string sql, object parameters = null)
{
var result = SqlQuery(sql, parameters);
return result == null ? default(T) : result.FirstOrDefault();
}
public virtual T SqlQuerySingle(string sql, params SugarParameter[] parameters)
{
var result = SqlQuery(sql, parameters);
return result == null ? default(T) : result.FirstOrDefault();
}
public virtual T SqlQuerySingle(string sql, List parameters)
{
var result = SqlQuery(sql, parameters);
return result == null ? default(T) : result.FirstOrDefault();
}
public virtual dynamic SqlQueryDynamic(string sql, object parameters = null)
{
var dt = this.GetDataTable(sql, parameters);
return dt == null ? null : this.Context.Utilities.DataTableToDynamic(dt);
}
public virtual dynamic SqlQueryDynamic(string sql, params SugarParameter[] parameters)
{
var dt = this.GetDataTable(sql, parameters);
return dt == null ? null : this.Context.Utilities.DataTableToDynamic(dt);
}
public dynamic SqlQueryDynamic(string sql, List parameters)
{
var dt = this.GetDataTable(sql, parameters);
return dt == null ? null : this.Context.Utilities.DataTableToDynamic(dt);
}
public virtual DataTable GetDataTable(string sql, params SugarParameter[] parameters)
{
var ds = GetDataSetAll(sql, parameters);
if (ds.Tables.Count != 0 && ds.Tables.Count > 0) return ds.Tables[0];
return new DataTable();
}
public virtual DataTable GetDataTable(string sql, object parameters)
{
return GetDataTable(sql, this.GetParameters(parameters));
}
public virtual DataTable GetDataTable(string sql, List parameters)
{
return parameters == null ? GetDataTable(sql) : GetDataTable(sql, parameters.ToArray());
}
public virtual DataSet GetDataSetAll(string sql, object parameters)
{
return GetDataSetAll(sql, this.GetParameters(parameters));
}
public virtual DataSet GetDataSetAll(string sql, List parameters)
{
return parameters == null ? GetDataSetAll(sql) : GetDataSetAll(sql, parameters.ToArray());
}
public virtual IDataReader GetDataReader(string sql, object parameters)
{
return GetDataReader(sql, this.GetParameters(parameters));
}
public virtual IDataReader GetDataReader(string sql, List parameters)
{
return parameters == null ? GetDataReader(sql) : GetDataReader(sql, parameters.ToArray());
}
public virtual object GetScalar(string sql, object parameters)
{
return GetScalar(sql, this.GetParameters(parameters));
}
public virtual object GetScalar(string sql, List parameters)
{
return parameters == null ? GetScalar(sql) : GetScalar(sql, parameters.ToArray());
}
public virtual int ExecuteCommand(string sql, object parameters)
{
return ExecuteCommand(sql, GetParameters(parameters));
}
public virtual int ExecuteCommand(string sql, List parameters)
{
return parameters == null ? ExecuteCommand(sql) : ExecuteCommand(sql, parameters.ToArray());
}
#endregion Methods
#region Helper
private void ExecuteProcessingSQL(ref string sql, SugarParameter[] parameters)
{
var result = this.ProcessingEventStartingSQL(sql, parameters);
sql = result.Key;
parameters = result.Value;
}
public virtual void ExecuteBefore(string sql, SugarParameter[] parameters)
{
if (this.IsEnableLogEvent)
{
var action = LogEventStarting;
if (action != null)
{
if (parameters == null || parameters.Length == 0)
{
action(sql, new SugarParameter[] { });
}
else
{
action(sql, parameters);
}
}
}
}
public virtual void ExecuteAfter(string sql, SugarParameter[] parameters)
{
var hasParameter = parameters.HasValue();
if (hasParameter)
{
foreach (var outputParameter in parameters.Where(it => it.Direction.IsIn(ParameterDirection.Output, ParameterDirection.InputOutput)))
{
var gobalOutputParamter = this.OutputParameters.Single(it => it.ParameterName == outputParameter.ParameterName);
outputParameter.Value = gobalOutputParamter.Value;
this.OutputParameters.Remove(gobalOutputParamter);
}
}
if (this.IsEnableLogEvent)
{
var action = LogEventCompleted;
if (action != null)
{
if (parameters == null || parameters.Length == 0)
{
action(sql, new SugarParameter[] { });
}
else
{
action(sql, parameters);
}
}
}
if (this.OldCommandType != 0)
{
this.CommandType = this.OldCommandType;
this.IsClearParameters = this.OldClearParameters;
this.OldCommandType = 0;
this.OldClearParameters = false;
}
}
public virtual SugarParameter[] GetParameters(object parameters, PropertyInfo[] propertyInfo = null)
{
if (parameters == null) return null;
return base.GetParameters(parameters, propertyInfo, this.SqlParameterKeyWord);
}
private bool IsAutoClose()
{
return this.Context.CurrentConnectionConfig.IsAutoCloseConnection && this.Transaction == null;
}
private bool IsMasterSlaveSeparation
{
get
{
return this.Context.CurrentConnectionConfig.SlaveConnectionConfigs.HasValue();
}
}
private void SetConnectionStart(string sql)
{
if (this.Transaction == null && this.IsMasterSlaveSeparation && IsRead(sql))
{
if (this.MasterConnection == null)
{
this.MasterConnection = this.Connection;
}
var saves = this.Context.CurrentConnectionConfig.SlaveConnectionConfigs.Where(it => it.HitRate > 0).ToList();
var currentIndex = UtilRandom.GetRandomIndex(saves.ToDictionary(it => saves.ToList().IndexOf(it), it => it.HitRate));
var currentSaveConnection = saves[currentIndex];
this.Connection = null;
this.Context.CurrentConnectionConfig.ConnectionString = currentSaveConnection.ConnectionString;
this.Connection = this.Connection;
if (this.SlaveConnections.IsNullOrEmpty() || !this.SlaveConnections.Any(it => EqualsConnectionString(it.ConnectionString, this.Connection.ConnectionString)))
{
if (this.SlaveConnections == null) this.SlaveConnections = new List();
this.SlaveConnections.Add(this.Connection);
}
}
}
private bool EqualsConnectionString(string connectionString1, string connectionString2)
{
var connectionString1Array = connectionString1.Split(';');
var connectionString2Array = connectionString2.Split(';');
var result = connectionString1Array.Except(connectionString2Array);
return result.Count() == 0;
}
private void SetConnectionEnd(string sql)
{
if (this.IsMasterSlaveSeparation && IsRead(sql) && this.Transaction == null)
{
this.Connection = this.MasterConnection;
this.Context.CurrentConnectionConfig.ConnectionString = this.MasterConnection.ConnectionString;
}
}
private bool IsRead(string sql)
{
var sqlLower = sql.ToLower();
var result = Regex.IsMatch(sqlLower, "[ ]*select[ ]") && !Regex.IsMatch(sqlLower, "[ ]*insert[ ]|[ ]*update[ ]|[ ]*delete[ ]");
return result;
}
#endregion Helper
}
}