313 lines
9.8 KiB
C#
313 lines
9.8 KiB
C#
using Microsoft.Data.SqlClient;
|
|
using System.Data;
|
|
using System.Security;
|
|
using System.Xml.Linq;
|
|
using System.Xml;
|
|
|
|
namespace e_suite.Database.Migrator.SqlWrapper;
|
|
|
|
public class SqlWrapper : ISqlWrapper
|
|
{
|
|
/// <summary>
|
|
/// contains the details of parameter including the value. Settings the value to null or DBNull.Value will result in a DBNull.Value being passed with the stored procedure call.
|
|
/// </summary>
|
|
private struct SqlParam
|
|
{
|
|
public string Name;
|
|
public SqlDbType Type;
|
|
public ParameterDirection Direction;
|
|
public object Value;
|
|
}
|
|
|
|
private const string ReturnValueParamName = "_ReturnValue";
|
|
private readonly IDbConnection _sqlConn;
|
|
private readonly List<SqlParam> _sqlParams;
|
|
private string _commandName = string.Empty;
|
|
private string _commandText = string.Empty;
|
|
|
|
public string CommandName
|
|
{
|
|
get => _commandName;
|
|
set
|
|
{
|
|
if (_commandName != value)
|
|
{
|
|
_commandName = value;
|
|
if (!string.IsNullOrEmpty(_commandText))
|
|
{
|
|
_commandText = string.Empty;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public string CommandText
|
|
{
|
|
get => _commandText;
|
|
set
|
|
{
|
|
if (_commandText != value)
|
|
{
|
|
_commandText = value;
|
|
if (!string.IsNullOrEmpty(_commandName))
|
|
{
|
|
_commandName = string.Empty;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an instance of the SqlCommand. Wraps setting everything needed to make a stored procedure call based on the parameters supplied.
|
|
/// </summary>
|
|
/// <returns>Prepared SqlCommand object ready for execution.</returns>
|
|
/// FxCop warning has been deliberately suppressed as the CommandText is only allowed to be a stored procedure name.
|
|
/// This is ensured by the hard coding of the CommandType.
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")]
|
|
private SqlCommand PrepareSqlCommand()
|
|
{
|
|
SqlCommand sqlCommand;
|
|
SqlCommand? tempSqlCommand = null;
|
|
|
|
try
|
|
{
|
|
tempSqlCommand = new SqlCommand
|
|
{
|
|
CommandTimeout = Timeout,
|
|
Connection = _sqlConn as SqlConnection
|
|
};
|
|
|
|
if (!string.IsNullOrEmpty(CommandName))
|
|
{
|
|
tempSqlCommand.CommandType = CommandType.StoredProcedure;
|
|
tempSqlCommand.CommandText = CommandName;
|
|
}
|
|
else if (!string.IsNullOrEmpty(CommandText))
|
|
{
|
|
tempSqlCommand.CommandType = CommandType.Text;
|
|
tempSqlCommand.CommandText = CommandText;
|
|
}
|
|
|
|
foreach (var sqlParam in _sqlParams)
|
|
{
|
|
if (sqlParam.Value is SecureString sqlParamValue)
|
|
{
|
|
tempSqlCommand.Parameters.AddSecure(sqlParam.Name, sqlParamValue);
|
|
}
|
|
else
|
|
{
|
|
var sqlParameter = tempSqlCommand.Parameters.Add(sqlParam.Name, sqlParam.Type);
|
|
|
|
if (sqlParam.Type == SqlDbType.VarChar)
|
|
{
|
|
sqlParameter.Size = -1;
|
|
}
|
|
sqlParameter.Direction = sqlParam.Direction;
|
|
sqlParameter.Value = sqlParam.Value;
|
|
}
|
|
}
|
|
|
|
sqlCommand = tempSqlCommand;
|
|
}
|
|
catch
|
|
{
|
|
tempSqlCommand?.Dispose();
|
|
throw;
|
|
}
|
|
|
|
return sqlCommand;
|
|
}
|
|
|
|
/// <summary>
|
|
/// retrieves the output parameters putting each into their respective SqlParam contained in the sqlParams list.
|
|
/// </summary>
|
|
/// <param name="sqlCommand">the SqlCommand object after execution so that the output parameters may be retrieved.</param>
|
|
private void RetrieveOutputParams(SqlCommand sqlCommand)
|
|
{
|
|
ParameterDirection[] outParamDirections = { ParameterDirection.InputOutput, ParameterDirection.Output, ParameterDirection.ReturnValue };
|
|
|
|
foreach (SqlParameter sqlParameter in sqlCommand.Parameters)
|
|
{
|
|
if (outParamDirections.Contains(sqlParameter.Direction))
|
|
{
|
|
for (int i = 0; i < _sqlParams.Count; i++)
|
|
{
|
|
SqlParam sqlParam = _sqlParams[i];
|
|
|
|
if (sqlParam.Name == sqlParameter.ParameterName)
|
|
{
|
|
sqlParam.Value = sqlParameter.Value;
|
|
_sqlParams[i] = sqlParam; //will this be needed?
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// class constructor. this will create and immediately open the database connection.
|
|
/// </summary>
|
|
public SqlWrapper(string connectionString) //constructor
|
|
{
|
|
_sqlConn = new SqlConnection(connectionString);
|
|
_sqlConn.Open();
|
|
_sqlParams = new List<SqlParam>();
|
|
}
|
|
|
|
public SqlWrapper(IDbConnection sqlConnection) //constructor
|
|
{
|
|
_sqlConn = sqlConnection;
|
|
_sqlConn.Open();
|
|
_sqlParams = new List<SqlParam>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Overrideable Dispose method. This will be called when the object is destroyed, either by ending a uses clause or by the garbage collector.
|
|
/// </summary>
|
|
/// <param name="disposing">states that this was called by the garbage collector</param>
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!IsDisposed)
|
|
{
|
|
if (disposing)
|
|
{
|
|
_sqlConn.Close();
|
|
}
|
|
}
|
|
IsDisposed = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// object destructor, will call the overridable Dispose method.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
public bool IsDisposed { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Removes all parameters from the internal parameter list.
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
_sqlParams.Clear();
|
|
}
|
|
|
|
public int ParamCount => _sqlParams.Count;
|
|
|
|
public int Timeout { get; set; } = 30;
|
|
|
|
public void AddParameter(string name, SqlDbType type, object value)
|
|
{
|
|
AddParameter(name, type, ParameterDirection.Input, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a new parameter to the stored procedure
|
|
/// </summary>
|
|
/// <param name="name">name of the parameter. For example @test the @ symbol is optional</param>
|
|
/// <param name="type">database type of the parameter</param>
|
|
/// <param name="direction">Specifies if this is an input or output parameter</param>
|
|
/// <param name="value">actual value for the parameter</param>
|
|
public void AddParameter(string name, SqlDbType type, ParameterDirection direction, object? value)
|
|
{
|
|
if (value == null)
|
|
{
|
|
value = DBNull.Value;
|
|
}
|
|
|
|
SqlParam sqlParam = new SqlParam
|
|
{
|
|
Name = name,
|
|
Type = type,
|
|
Direction = direction,
|
|
Value = value
|
|
};
|
|
|
|
_sqlParams.Add(sqlParam);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the current value of a parameter
|
|
/// </summary>
|
|
/// <param name="name">name of the parameter that you need the value for</param>
|
|
/// <returns>either the value of the named parameter, or null if it does not exist</returns>
|
|
public object? GetParamValue(string name)
|
|
{
|
|
foreach (var sqlParam in _sqlParams)
|
|
{
|
|
if (sqlParam.Name == name)
|
|
{
|
|
return sqlParam.Value;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the procedures return value
|
|
/// </summary>
|
|
/// <returns>the return value from the procedure call</returns>
|
|
public object? GetReturnValue()
|
|
{
|
|
return GetParamValue(ReturnValueParamName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Execute the stored procedure without the expectation of any result sets being returned.
|
|
/// note: output parameters will be set when the method completes.
|
|
/// </summary>
|
|
public void Execute()
|
|
{
|
|
AddParameter(ReturnValueParamName, SqlDbType.Int, ParameterDirection.ReturnValue, null);
|
|
using (SqlCommand sqlCommand = PrepareSqlCommand())
|
|
{
|
|
sqlCommand.ExecuteNonQuery();
|
|
RetrieveOutputParams(sqlCommand);
|
|
}
|
|
}
|
|
|
|
|
|
public XmlReader ExecuteXmlReader()
|
|
{
|
|
using (SqlCommand sqlCommand = PrepareSqlCommand())
|
|
{
|
|
return sqlCommand.ExecuteXmlReader();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Execute the stored procedure with the expection of an XML Stream result set.
|
|
/// </summary>
|
|
/// <returns>XML document containing the result of the stored procedure call</returns>
|
|
public XmlDocument ExecuteXmlDocument()
|
|
{
|
|
using (XmlReader xReader = ExecuteXmlReader())
|
|
{
|
|
XmlDocument xmlDocument = new XmlDocument();
|
|
xmlDocument.Load(xReader);
|
|
return xmlDocument;
|
|
}
|
|
}
|
|
|
|
public XDocument ExecuteXDocument()
|
|
{
|
|
using (XmlReader xReader = ExecuteXmlReader())
|
|
{
|
|
XDocument xmlDocument = XDocument.Load(xReader);
|
|
return xmlDocument;
|
|
}
|
|
}
|
|
|
|
public IDataReader ExecuteReader()
|
|
{
|
|
using (SqlCommand sqlCommand = PrepareSqlCommand())
|
|
{
|
|
return sqlCommand.ExecuteReader();
|
|
}
|
|
}
|
|
} |