193 lines
9.2 KiB
C#
193 lines
9.2 KiB
C#
namespace LaaProduction.Data.SQL
|
|
{
|
|
using LaaProduction.Data.SQL.Interfaces;
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.SqlClient;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
/// <summary>
|
|
/// A wrapper class around the <see cref="System.Data.SqlClient"/>.
|
|
/// Exposes <see cref="System.Data.SqlClient.SqlConnection"/>, <see cref="System.Data.SqlClient.SqlCommand"/> and <see cref="System.Data.SqlClient.SqlDataReader"/> classes
|
|
/// in a fluent manner, all exposed methods can be chained in a single C# query.
|
|
/// </summary>
|
|
public class SQLConnection : ISQLConnection
|
|
{
|
|
private readonly string connectionString;
|
|
private readonly Action<string> errorCallback;
|
|
|
|
/// <summary>
|
|
/// When <paramref name="connectionString"/> is null, white space or is not a valid connection string exception is thrown.
|
|
/// </summary>
|
|
/// <param name="connectionString"><see cref="System.String"/> - SQL connection string.</param>
|
|
public SQLConnection(string connectionString)
|
|
{
|
|
var connectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
|
|
|
|
this.connectionString = connectionStringBuilder.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// When <paramref name="connectionString"/> is null, white space or is not a valid connection string exception is thrown.
|
|
/// Additionaly accepts <see cref="System.Action{System.String}"/> for error handling.
|
|
/// Whenever the sql query throws error on execution, this will be passesd within the callback.
|
|
/// </summary>
|
|
/// <param name="connectionString"><see cref="System.String"/> - SQL connection string.</param>
|
|
/// <param name="errorCallback"><see cref="System.Action{System.String}"/> - error handler for SQL execution errors.</param>
|
|
public SQLConnection(string connectionString, Action<string> errorCallback = null)
|
|
: this(connectionString)
|
|
=> this.errorCallback = errorCallback;
|
|
|
|
/// <summary>
|
|
/// Creates a <see cref="LaaProduction.Data.SQL.ISQLCommand"/> wrapper that accepts a SQL query string.
|
|
/// </summary>
|
|
/// <param name="commandText"><see cref="System.String"/> - SQL query string</param>
|
|
/// <returns><see cref="LaaProduction.Data.SQL.ISQLCommand"/> - that exposes basic functionalities from the <see cref="System.Data.SqlClient.SqlCommand" />.</returns>
|
|
public ISQLCommand CreateCommand(string commandText)
|
|
=> new SQLCommand(this, commandText);
|
|
|
|
/// <summary>
|
|
/// Static method that creates a <see cref="LaaProduction.Data.SQL.ISQLConnection"/> client with given connection string.
|
|
/// </summary>
|
|
/// <param name="connectionString"><see cref="System.String"/> - SQL connection string.</param>
|
|
/// <returns><see cref="LaaProduction.Data.SQL.ISQLConnection"/></returns>
|
|
public static ISQLConnection CreateSQLConnection(string connectionString)
|
|
=> new SQLConnection(connectionString);
|
|
|
|
/// <summary>
|
|
/// Static method that creates a <see cref="LaaProduction.Data.SQL.ISQLConnection"/> client with given connection string and error callback that receives all error messages.
|
|
/// </summary>
|
|
/// <param name="connectionString"><see cref="System.String"/> - SQL connection string.</param>
|
|
/// <param name="errorCallback"><see cref="System.Action{System.String}"/> - error handler for SQL execution errors.</param>
|
|
/// <returns><see cref="LaaProduction.Data.SQL.ISQLConnection"/></returns>
|
|
public static ISQLConnection CreateSQLConnection(string connectionString, Action<string> errorCallback = null)
|
|
=> new SQLConnection(connectionString, errorCallback);
|
|
|
|
/// <summary>
|
|
/// Internal method called from <see cref="LaaProduction.Data.SQL.ISQLCommand"/>.
|
|
/// Like in a <see cref="System.Data.SqlClient.SqlCommand"/> performs INSERT, UPDATE, DELETE queries and returns the number of rows affected.
|
|
/// </summary>
|
|
/// <param name="command"><see cref="System.String"/> - SQL query string</param>
|
|
/// <returns><see cref="System.Int32"/> - the number of rows affected.</returns>
|
|
internal int ExecuteNonQuery(SQLCommand command)
|
|
{
|
|
var rowsAffected = 0;
|
|
|
|
using (var sqlConnection = new SqlConnection(this.connectionString))
|
|
{
|
|
sqlConnection.OpenWithErrorHandling(this.errorCallback);
|
|
|
|
using (var sqlCommand = sqlConnection.CreateCommand())
|
|
{
|
|
sqlCommand.CommandText = command.CommandText;
|
|
|
|
sqlCommand.Parameters.AddRange(command.Parameters);
|
|
|
|
rowsAffected = sqlCommand.ExecuteNonQuery();
|
|
|
|
sqlCommand.Parameters.Clear();
|
|
}
|
|
}
|
|
|
|
return rowsAffected;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Internal method called from <see cref="LaaProduction.Data.SQL.ISQLCommand"/>.
|
|
/// Like in a <see cref="System.Data.SqlClient.SqlCommand"/> performs SELECT queries and returns a enumerable of the results readed.
|
|
/// </summary>
|
|
/// <typeparam name="T">Is the type that returns the <see cref="System.Func{IFluentSQLReader, T} expression"/></typeparam>
|
|
/// <param name="command"><see cref="System.String"/> - SQL query string</param>
|
|
/// <param name="expression">Expression that reads specified data from the <see cref="LaaProduction.Data.SQL.ISQLReader"/>.</param>
|
|
/// <returns><see cref="System.Collections.Generic.IEnumerable{T}"/></returns>
|
|
internal IEnumerable<T> ExecuteReader<T>(SQLCommand command, Func<ISQLReader, T> expression)
|
|
{
|
|
using (var sqlConnection = new SqlConnection(this.connectionString))
|
|
{
|
|
sqlConnection.OpenWithErrorHandling(this.errorCallback);
|
|
|
|
using (var sqlCommand = sqlConnection.CreateCommand())
|
|
{
|
|
sqlCommand.CommandText = command.CommandText;
|
|
|
|
sqlCommand.Parameters.AddRange(command.Parameters);
|
|
|
|
using (SQLReader sqlReader = sqlCommand.ExecuteReader())
|
|
{
|
|
sqlCommand.Parameters.Clear();
|
|
|
|
while (sqlReader.Read())
|
|
{
|
|
yield return expression(sqlReader);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Internal method called from <see cref="LaaProduction.Data.SQL.ISQLCommand"/>.
|
|
/// Like in a <see cref="System.Data.SqlClient.SqlCommand"/> performs SELECT, READ, UPDATE, DELETE queries and returns first column from the first row from the result.
|
|
/// </summary>
|
|
/// <typeparam name="T">From user specified.</typeparam>
|
|
/// <param name="command"><see cref="System.String"/> - SQL query string</param>
|
|
/// <param name="expression">Expression that reads specified data from the <see cref="LaaProduction.Data.SQL.ISQLReader"/>.</param>
|
|
/// <returns><see cref="System.Collections.Generic.IEnumerable{T}"/></returns>
|
|
internal T ExecuteScalar<T>(SQLCommand command, Func<ISQLReader, T> expression)
|
|
{
|
|
var scalarResult = default(T);
|
|
|
|
using (var sqlConnection = new SqlConnection(this.connectionString))
|
|
{
|
|
this.OpenWithErrorHandling(sqlConnection, this.errorCallback);
|
|
|
|
using (var sqlCommand = sqlConnection.CreateCommand())
|
|
{
|
|
sqlCommand.CommandText = command.CommandText;
|
|
|
|
sqlCommand.Parameters.AddRange(command.Parameters);
|
|
|
|
var scalarObject = sqlCommand.ExecuteScalar();
|
|
|
|
sqlCommand.Parameters.Clear();
|
|
|
|
if (scalarObject is T scalarValue)
|
|
{
|
|
scalarResult = scalarValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return scalarResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is same like <see cref="LaaProduction.Data.SQL.SQLConnection.ExecuteReader{T}(SQLCommand, Func{ISQLReader, T})"/> but returns only the first data row.
|
|
/// </summary>
|
|
/// <typeparam name="T">From user specified.</typeparam>
|
|
/// <param name="command"><see cref="System.String"/> - SQL query string</param>
|
|
/// <param name="expression">Expression that reads specified data from the <see cref="LaaProduction.Data.SQL.ISQLReader"/>.</param>
|
|
/// <returns><see cref="{T}"/></returns>
|
|
internal T FirstOrDefault<T>(SQLCommand command, Func<ISQLReader, T> expression)
|
|
=> this
|
|
.ExecuteReader(command, expression)
|
|
.FirstOrDefault();
|
|
|
|
private void OpenWithErrorHandling(SqlConnection connection, Action<string> errorCallback)
|
|
{
|
|
connection.FireInfoMessageEventOnUserErrors = true;
|
|
connection.InfoMessage += (sender, args) =>
|
|
{
|
|
var errors = new StringBuilder();
|
|
|
|
foreach (SqlError e in args.Errors)
|
|
{
|
|
errors.Append($"{e.Server}|{e.Source}|{e.S}|{e.Class}|{e.Number}");
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|