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;
///
/// A wrapper class around the .
/// Exposes , and classes
/// in a fluent manner, all exposed methods can be chained in a single C# query.
///
public class SQLConnection : ISQLConnection
{
private readonly string connectionString;
private readonly Action errorCallback;
///
/// When is null, white space or is not a valid connection string exception is thrown.
///
/// - SQL connection string.
public SQLConnection(string connectionString)
{
var connectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
this.connectionString = connectionStringBuilder.ToString();
}
///
/// When is null, white space or is not a valid connection string exception is thrown.
/// Additionaly accepts for error handling.
/// Whenever the sql query throws error on execution, this will be passesd within the callback.
///
/// - SQL connection string.
/// - error handler for SQL execution errors.
public SQLConnection(string connectionString, Action errorCallback = null)
: this(connectionString)
=> this.errorCallback = errorCallback;
///
/// Creates a wrapper that accepts a SQL query string.
///
/// - SQL query string
/// - that exposes basic functionalities from the .
public ISQLCommand CreateCommand(string commandText)
=> new SQLCommand(this, commandText);
///
/// Static method that creates a client with given connection string.
///
/// - SQL connection string.
///
public static ISQLConnection CreateSQLConnection(string connectionString)
=> new SQLConnection(connectionString);
///
/// Static method that creates a client with given connection string and error callback that receives all error messages.
///
/// - SQL connection string.
/// - error handler for SQL execution errors.
///
public static ISQLConnection CreateSQLConnection(string connectionString, Action errorCallback = null)
=> new SQLConnection(connectionString, errorCallback);
///
/// Internal method called from .
/// Like in a performs INSERT, UPDATE, DELETE queries and returns the number of rows affected.
///
/// - SQL query string
/// - the number of rows affected.
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;
}
///
/// Internal method called from .
/// Like in a performs SELECT queries and returns a enumerable of the results readed.
///
/// Is the type that returns the
/// - SQL query string
/// Expression that reads specified data from the .
///
internal IEnumerable ExecuteReader(SQLCommand command, Func 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);
}
}
}
}
}
///
/// Internal method called from .
/// Like in a performs SELECT, READ, UPDATE, DELETE queries and returns first column from the first row from the result.
///
/// From user specified.
/// - SQL query string
/// Expression that reads specified data from the .
///
internal T ExecuteScalar(SQLCommand command, Func 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;
}
///
/// Is same like but returns only the first data row.
///
/// From user specified.
/// - SQL query string
/// Expression that reads specified data from the .
///
internal T FirstOrDefault(SQLCommand command, Func expression)
=> this
.ExecuteReader(command, expression)
.FirstOrDefault();
private void OpenWithErrorHandling(SqlConnection connection, Action 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}");
}
};
}
}
}