245 lines
8.5 KiB
C#
245 lines
8.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Data.SqlClient;
|
|
using System.Reflection;
|
|
using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching;
|
|
using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching.Database;
|
|
|
|
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers
|
|
{
|
|
/// <summary>
|
|
/// Reader implementation for SQL Server based data source.
|
|
/// DataSource = SQL Server connection string
|
|
/// QueryTemplate = SQL query containing QUERYPARAM placeholder
|
|
/// </summary>
|
|
public class DatabaseReader : IDataStorageReader
|
|
{
|
|
private readonly ReaderCfg cfg;
|
|
|
|
public ReaderDiagnosticResult TestSource(bool enableDiagnostics)
|
|
{
|
|
ReaderDiagnosticResult result = new ReaderDiagnosticResult();
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(cfg.DataSource))
|
|
{
|
|
result.Success = false;
|
|
result.Message = "Data source is empty.";
|
|
return result;
|
|
}
|
|
|
|
if (enableDiagnostics)
|
|
result.Diagnostics.Add("Opening SQL connection...");
|
|
|
|
using (SqlConnection connection = new SqlConnection(cfg.DataSource))
|
|
{
|
|
connection.Open();
|
|
|
|
if (enableDiagnostics)
|
|
result.Diagnostics.Add("Connection opened successfully.");
|
|
|
|
using (SqlCommand command = new SqlCommand("SELECT 1", connection))
|
|
{
|
|
object val = command.ExecuteScalar();
|
|
|
|
if (enableDiagnostics)
|
|
result.Diagnostics.Add("Test query executed. Result=" + val);
|
|
}
|
|
}
|
|
|
|
result.Success = true;
|
|
result.Message = "Connection to SQL Server OK.";
|
|
return result;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
result.Success = false;
|
|
result.Message = "Failed to connect to SQL Server.";
|
|
|
|
if (enableDiagnostics)
|
|
result.Diagnostics.Add(ex.ToString());
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
public ReaderDiagnosticResult TestQuery(bool enableDiagnostics)
|
|
{
|
|
ReaderDiagnosticResult result = new ReaderDiagnosticResult();
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(cfg.QueryTemplate))
|
|
{
|
|
result.Success = false;
|
|
result.Message = "Query template is empty.";
|
|
return result;
|
|
}
|
|
|
|
string sql = PrepareSqlText(cfg.QueryTemplate);
|
|
|
|
if (enableDiagnostics)
|
|
{
|
|
result.Diagnostics.Add("Original template:");
|
|
result.Diagnostics.Add(cfg.QueryTemplate);
|
|
|
|
result.Diagnostics.Add("Prepared SQL:");
|
|
result.Diagnostics.Add(sql);
|
|
}
|
|
|
|
using (SqlConnection connection = new SqlConnection(cfg.DataSource))
|
|
using (SqlCommand command = new SqlCommand(sql, connection))
|
|
{
|
|
// dummy parameter
|
|
command.Parameters.AddWithValue("@value", "TEST");
|
|
|
|
if (enableDiagnostics)
|
|
result.Diagnostics.Add("Parameter @value = TEST");
|
|
|
|
connection.Open();
|
|
|
|
object val = command.ExecuteScalar();
|
|
|
|
if (enableDiagnostics)
|
|
result.Diagnostics.Add("Query executed successfully.");
|
|
|
|
result.Data = val; // can be null → OK
|
|
}
|
|
|
|
result.Success = true;
|
|
result.Message = "Query executed successfully.";
|
|
return result;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
result.Success = false;
|
|
result.Message = "Query execution failed.";
|
|
|
|
if (enableDiagnostics)
|
|
result.Diagnostics.Add(ex.ToString());
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
public DatabaseReader(ReaderCfg cfg)
|
|
{
|
|
this.cfg = cfg ?? throw new ArgumentNullException(nameof(cfg));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads data from SQL Server and returns matched data.
|
|
/// If query returns 1 column, scalar value is returned.
|
|
/// If query returns multiple columns, Dictionary<string, object> is returned.
|
|
/// </summary>
|
|
public object GetData(Interfaces.PublicModels.DataQuery query)
|
|
{
|
|
if (query == null)
|
|
throw new ArgumentNullException(nameof(query));
|
|
|
|
ReaderDiagnosticResult connectResult = ConnectToSource(true);
|
|
if (!connectResult.Success)
|
|
throw new InvalidOperationException(connectResult.Message);
|
|
|
|
string sqlText = PrepareSqlText(cfg.QueryTemplate);
|
|
object queryValue = ExtractQueryValue(query);
|
|
|
|
using (SqlConnection connection = new SqlConnection(cfg.DataSource))
|
|
using (SqlCommand command = new SqlCommand(sqlText, connection))
|
|
{
|
|
AddQueryParameters(command, queryValue);
|
|
|
|
connection.Open();
|
|
|
|
using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow))
|
|
{
|
|
DatabaseSearchResult result = new DatabaseSearchResult();
|
|
result.Query = sqlText;
|
|
|
|
if (!reader.Read())
|
|
{
|
|
result.Found = false;
|
|
return result;
|
|
}
|
|
|
|
result.Found = true;
|
|
|
|
for (int i = 0; i < reader.FieldCount; i++)
|
|
{
|
|
object value = reader.GetValue(i);
|
|
result.Values[reader.GetName(i)] = value == DBNull.Value ? null : value;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates database connectivity and basic query readiness.
|
|
/// </summary>
|
|
public ReaderDiagnosticResult ConnectToSource(bool validateExistence)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(cfg.DataSource))
|
|
return ReaderDiagnosticResult.Failure("Data source must not be empty.");
|
|
|
|
if (string.IsNullOrWhiteSpace(cfg.QueryTemplate))
|
|
return ReaderDiagnosticResult.Failure("Query template must not be empty.");
|
|
|
|
try
|
|
{
|
|
using (SqlConnection connection = new SqlConnection(cfg.DataSource))
|
|
{
|
|
connection.Open();
|
|
|
|
if (validateExistence)
|
|
{
|
|
using (SqlCommand command = new SqlCommand("SELECT 1", connection))
|
|
{
|
|
command.ExecuteScalar();
|
|
}
|
|
}
|
|
}
|
|
|
|
return ReaderDiagnosticResult.SuccessResult();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return ReaderDiagnosticResult.Failure(
|
|
string.Format("Failed to connect to SQL Server data source. {0}", ex.Message));
|
|
}
|
|
}
|
|
|
|
private static string PrepareSqlText(string queryTemplate)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(queryTemplate))
|
|
throw new ArgumentException("Query template must not be empty.", nameof(queryTemplate));
|
|
|
|
if (!queryTemplate.Contains("QUERYPARAM"))
|
|
throw new InvalidOperationException("Query template must contain QUERYPARAM placeholder.");
|
|
|
|
return queryTemplate.Replace("QUERYPARAM", "@value");
|
|
}
|
|
|
|
private static void AddQueryParameters(SqlCommand command, object queryValue)
|
|
{
|
|
command.Parameters.Clear();
|
|
|
|
SqlParameter parameter = command.Parameters.Add("@value", SqlDbType.Variant);
|
|
parameter.Value = queryValue ?? DBNull.Value;
|
|
}
|
|
|
|
private static object ExtractQueryValue(Interfaces.PublicModels.DataQuery query)
|
|
{
|
|
if (query == null)
|
|
throw new ArgumentNullException(nameof(query));
|
|
|
|
if (query.QueryParams == null || query.QueryParams.Count == 0)
|
|
throw new InvalidOperationException("DataQuery does not contain any query parameter.");
|
|
|
|
return query.QueryParams[0];
|
|
}
|
|
}
|
|
} |