176 lines
8.0 KiB
C#
176 lines
8.0 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)
|
|
=> this.connectionString = connectionString;
|
|
|
|
/// <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>
|
|
/// 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))
|
|
{
|
|
this.OpenWithErrorHandling(sqlConnection);
|
|
|
|
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))
|
|
{
|
|
this.OpenWithErrorHandling(sqlConnection);
|
|
|
|
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);
|
|
|
|
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)
|
|
{
|
|
connection.FireInfoMessageEventOnUserErrors = true;
|
|
connection.InfoMessage += (sender, args) =>
|
|
{
|
|
var errors = new StringBuilder();
|
|
|
|
foreach (SqlError e in args.Errors)
|
|
{
|
|
errors.Append($"Server:{e.Server}|Source:{e.Source}|State:{e.State}|Class:{e.Class}|Number:{e.Number}|Line:{e.LineNumber}|Message:{e.Message}");
|
|
}
|
|
|
|
this.errorCallback?.Invoke(errors.ToString());
|
|
};
|
|
|
|
connection.Open();
|
|
}
|
|
}
|
|
}
|