diff --git a/anbs_cpdb/Classes/MySqlEngine.cs b/anbs_cpdb/Classes/MySqlEngine.cs index a5ef494..20dee85 100644 --- a/anbs_cpdb/Classes/MySqlEngine.cs +++ b/anbs_cpdb/Classes/MySqlEngine.cs @@ -20,14 +20,14 @@ public class MySqlEngine: IDbEngine /// public string ConnectionString { get; set; } - #region Небезопасные методы + #region Базовые операции /// /// Выполняем команду /// /// Запрос - /// Данные запроса - /// Успешно ли (есть ли хотя бы одна затронутая строки) выполнена команда - public async Task ExecuteAsync (string sql, object model) + /// Данные запроса + /// Количество затронутых строк + public async Task ExecuteAsync (string sql, object values) { // Подключаемся к БД await using MySqlConnection connection = new(ConnectionString); @@ -36,17 +36,25 @@ public class MySqlEngine: IDbEngine await connection.OpenAsync(); // Выполняем команду и выводим результат - return await connection.ExecuteAsync(sql, model) > 0; + return await connection.ExecuteAsync(sql, values); } /// - /// Запрос на получение одной строки + /// Выполняем команду + /// + /// Запрос + /// Данные запроса + /// Количество затронутых строк + public int Execute (string sql, object values) => ExecuteAsync(sql, values).GetAwaiter().GetResult(); + + /// + /// Запрос /// /// Тип передаваемого значения /// Запрос - /// Данные запроса - /// Возвращает тип или значение по умолчанию - public async Task QueryRowAsync (string sql, object model) + /// Данные запроса + /// Возвращает массив типа или значение по умолчанию + public async Task> QueryAsync (string sql, object values) { // Подключаемся к БД await using MySqlConnection connection = new(ConnectionString); @@ -55,7 +63,7 @@ public class MySqlEngine: IDbEngine await connection.OpenAsync(); // Выполняем запрос и выводим результат - return await connection.QueryFirstOrDefaultAsync(sql, model); + return await connection.QueryAsync(sql, values); } /// @@ -63,9 +71,18 @@ public class MySqlEngine: IDbEngine /// /// Тип передаваемого значения /// Запрос - /// Данные запроса + /// Данные запроса /// Возвращает массив типа или значение по умолчанию - public async Task> QueryAsync (string sql, object model) + public IEnumerable Query (string sql, object values) => QueryAsync(sql, values).GetAwaiter().GetResult(); + + /// + /// Запрос строки + /// + /// Тип передаваемого значения + /// Запрос + /// Данные запроса + /// Возвращает массив типа или значение по умолчанию + public async Task QueryRowAsync (string sql, object values) { // Подключаемся к БД await using MySqlConnection connection = new(ConnectionString); @@ -74,105 +91,275 @@ public class MySqlEngine: IDbEngine await connection.OpenAsync(); // Выполняем запрос и выводим результат - return await connection.QueryAsync(sql, model); + return await connection.QuerySingleOrDefaultAsync(sql, values); } + /// + /// Запрос строки + /// + /// Тип передаваемого значения + /// Запрос + /// Данные запроса + /// Возвращает массив типа или значение по умолчанию + public T? QueryRow (string sql, object values) => QueryRowAsync(sql, values).GetAwaiter().GetResult(); + #endregion - #region Получение + + #region Получение данных + /// + /// Получает массив данных (SELECT * FROM...) + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Массив результата запроса + public async Task> GetResultsAsync (string sql, object values) => await QueryAsync(sql, values); /// - /// Выборка данных из таблицы + /// Получает массив данных (SELECT * FROM...) /// - /// Тип данных - /// Имя таблицы - /// Выбор столбцов таблицы, которые должны попасть в выборку (пустая -- все) - /// Массив значений столбцов, которые должны попасть в выборку - /// Сортировка - /// Сколько максимально элементов должно быть в выборке (0 -- без ограничения) - /// Массив типа - public async Task> SelectAsync(string table, string[] columns, - List> where, string? orderBy, int limit = 0) + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Массив результата запроса + public IEnumerable GetResults (string sql, object values) => GetResultsAsync(sql, values).GetAwaiter().GetResult(); + + /// + /// Получает строку в массиве данных + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Строки данных или null + public async Task GetRowAsync (string sql, object values) { - // Формирую запрос + // Подключаемся к БД + await using MySqlConnection connection = new(ConnectionString); + + // Открываем соединение + await connection.OpenAsync(); + + // Выполняем запрос и выводим результат + return await connection.QuerySingleOrDefaultAsync(sql, values); + } + + /// + /// Получает строку в массиве данных + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Строки данных или null + public T? GetRow (string sql, object values) => GetRowAsync(sql, values).GetAwaiter().GetResult(); + + /// + /// Получает колонку в массиве данных + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Колонка данных или null + public async Task> GetColAsync (string sql, object values) + where T : IComparable, IConvertible, IEquatable => await QueryAsync(sql, values); + + /// + /// Получает колонку в массиве данных + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Колонка данных или null + public IEnumerable GetCol (string sql, object values) where T : IComparable, IConvertible, IEquatable => + GetColAsync(sql, values).GetAwaiter().GetResult(); + + /// + /// Получение значение единичного поля + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Поле или null + public async Task GetVarAsync (string sql, object values) where T : IComparable, IConvertible, IEquatable + { + // Подключаемся к БД + await using MySqlConnection connection = new(ConnectionString); + + // Открываем соединение + await connection.OpenAsync(); + + // Выполняем запрос и выводим результат + return await connection.QuerySingleOrDefaultAsync(sql, values); + } + + /// + /// Получение значение единичного поля + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Поле или null + public T? GetVar (string sql, object values) where T : IComparable, IConvertible, IEquatable => + GetVarAsync(sql, values).GetAwaiter().GetResult(); + + #endregion + + #region CRUD данные + + /// + /// Вставляет данные в таблицу + /// + /// Класс данных + /// Данные + /// Имя таблицы + /// Результат выполнения + public async Task InsertAsync (T data, string tableName) where T : class + { + // Получение список имён свойств в data + List propertyNamesList = (from dataProperty in data.GetType().GetProperties() select dataProperty.Name).ToList(); + + // Получаем список имён в data, обрамленные @ + List propertyValuesList = propertyNamesList.Select(static propertyName => $"@{propertyName}").ToList(); + + //Получаем строку имён свойств + string propertyNames = string.Join(", ", propertyNamesList.ToArray()); + + // Получаем строку имён свойств, обрамленных @ + string propertyValues = string.Join(", ", propertyValuesList.ToArray()); + + // Создаю соединение + await using MySqlConnection connection = new(ConnectionString); + + // Создаю запрос string sql = $""" - SELECT - {(columns.Any() ? string.Join(", ", columns) : "*")} - FROM {table} - """; - - // Создаю массив where параметров - List whereCondition = new(); - - // Создаю массив значений - List paramsValues = new(); - - // Если заданы параметры where - if (where.Any()) - { - // - то формирую массив where из where-запроса - whereCondition.AddRange(where.Select(static whereItem => $"{whereItem.Key}=@{whereItem.Key}")); - // - и значения параметров - paramsValues.AddRange(where.Select(static whereItem => $"@{whereItem.Key}={whereItem.Value}")); - } - - // Если массив where параметров не пуст - if (whereCondition.Any()) - // - то добавляю к запросу - sql += $" WHERE {string.Join(", ", whereCondition.ToArray())}"; - - // Если добавлена сортировка - if (orderBy != null) - // - то добавляю сортировку к запросу - sql += $" ORDER BY {orderBy}"; - - // Если установлено запрашиваемое число элементов - if (limit > 0) - // - то вводим ограничение - sql += $" LIMIT {limit}"; - - // Осуществляю запрос и возвращаю результат - return await QueryAsync(sql, paramsValues.ToArray()); - } - - /// - /// Выборка строки из таблицы - /// - /// Тип данных - /// Имя таблицы - /// Выбор столбцов таблицы, которые должны попасть в выборку (пустая -- все) - /// Массив значений столбцов, которые должны попасть в выборку - /// Сортировка - /// Тип или null - public async Task SelectRowAsync(string table, string[] columns, List> where, - string? orderBy = null) => (await SelectAsync(table, columns, where, orderBy, 1)).FirstOrDefault(); - - #endregion - - #region Вычисление числа элементов в таблице -/// -/// Вычисляет число строк в таблице -/// -/// Таблица -/// Число строк в таблице - public async Task CountAsync(string table) - { - // Задаю запрос - string sql = $"SELECT COUNT(*) FROM {table}"; + INSERT + INTO {tableName} ({propertyNames}) + VALUES ({propertyValues}) + """; // Выполняю запрос - return (await QueryAsync(sql, new())).FirstOrDefault(); + return await connection.ExecuteAsync(sql, data) > 0; } + /// + /// Вставляет данные в таблицу + /// + /// Класс данных + /// Данные + /// Имя таблицы + /// Результат выполнения + public bool Insert (T data, string tableName) where T : class => InsertAsync(data, tableName).GetAwaiter().GetResult(); + + /// + /// Обновляет строку в таблице + /// + /// Класс данных + /// Данные + /// Имя таблицы + /// Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data + /// Результат выполнения + public async Task UpdateAsync (T data, string tableName, string whereConditionColumn) where T : class + { + // Получение список имён свойств в data + List propertyNamesList = (from dataProperty in data.GetType().GetProperties() + where dataProperty.Name != whereConditionColumn + select dataProperty.Name).ToList(); + + // Получаем список имён в data, обрамленные @ + List propertyKeyValuesList = propertyNamesList.Select(static propertyName => $"{propertyName}=@{propertyName}").ToList(); + + // Получаем строку имён свойств, обрамленных @ + string properties = string.Join(", ", propertyKeyValuesList.ToArray()); + + // Создаю соединение + await using MySqlConnection connection = new(ConnectionString); + + // Создаю запрос + string sql = $""" + UPDATE + {tableName} + SET + ({properties}) + WHERE + {whereConditionColumn}=@{whereConditionColumn} + """; + + // Выполняю запрос + return await connection.ExecuteAsync(sql, data) > 0; + } + + /// + /// Обновляет строку в таблице + /// + /// Класс данных + /// Данные + /// Имя таблицы + /// Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data + /// Результат выполнения + public bool Update (T data, string tableName, string whereConditionColumn) where T : class => + UpdateAsync(data, tableName, whereConditionColumn).GetAwaiter().GetResult(); + + /// + /// Удаляет строки + /// + /// Имя таблицы + /// Условие + /// Результат выполнения + public async Task DeleteAsync (string tableName, KeyValue where) + { + // Создаю соединение + await using MySqlConnection connection = new(ConnectionString); + + // Создаю запрос + string sql = $""" + DELETE FROM + {tableName} + WHERE + {where.Key}=@{where.Key} + """; + + // Выполняю запрос + return await connection.ExecuteAsync(sql, new { where.Value }) > 0; + } + + /// + /// Удаляет строки + /// + /// Имя таблицы + /// Условие + /// Результат выполнения + public bool Delete (string tableName, KeyValue where) => DeleteAsync(tableName, where).GetAwaiter().GetResult(); + + /// + /// Удаляет строку + /// + /// Имя таблицы + /// Условие + /// Результат выполнения + public async Task DeleteRowAsync (string tableName, KeyValue where) + { + // Создаю соединение + await using MySqlConnection connection = new(ConnectionString); + + // Создаю запрос + string sql = $""" + DELETE FROM + {tableName} + WHERE + {where.Key}=@{where.Key} + LIMIT 1 + """; + + // Выполняю запрос + return await connection.ExecuteAsync(sql, new { where.Value }) > 0; + } + + /// + /// Удаляет строку + /// + /// Имя таблицы + /// Условие + /// Результат выполнения + public bool DeleteRow (string tableName, KeyValue where) => DeleteRowAsync(tableName, where).GetAwaiter().GetResult(); #endregion - - public async Task InsertAsync (string table, T entity, KeyValue primaryIndex) => throw new NotImplementedException(); - - public async Task InsertUpdateAsync (string table, T entity) => throw new NotImplementedException(); - - public async Task UpdateAsync (string table, T entity, KeyValue where) => throw new NotImplementedException(); - - public async Task DeleteAsync (string table, KeyValue where) => throw new NotImplementedException(); - - public async Task DeleteRowAsync (string table, KeyValue where) => throw new NotImplementedException(); } \ No newline at end of file diff --git a/anbs_cpdb/Interfaces/IDbEngine.cs b/anbs_cpdb/Interfaces/IDbEngine.cs index 0150450..672eed1 100644 --- a/anbs_cpdb/Interfaces/IDbEngine.cs +++ b/anbs_cpdb/Interfaces/IDbEngine.cs @@ -12,84 +12,206 @@ public interface IDbEngine /// string ConnectionString { get; set; } - #region Небезопасные методы - - Task ExecuteAsync (string sql, object model); + #region Базовые операции /// - /// Запрос на получение одной строки + /// Выполняем команду /// - /// Тип передаваемого значения /// Запрос - /// Данные запроса - /// Возвращает тип или значение по умолчанию - Task QueryRowAsync (string sql, object model); + /// Данные запроса + /// Количество затронутых строк + Task ExecuteAsync (string sql, object values); + + /// + /// Выполняем команду + /// + /// Запрос + /// Данные запроса + /// Количество затронутых строк + int Execute (string sql, object values); /// /// Запрос /// /// Тип передаваемого значения /// Запрос - /// Данные запроса + /// Данные запроса /// Возвращает массив типа или значение по умолчанию - Task> QueryAsync (string sql, object model); - - #endregion - - #region Получение + Task> QueryAsync (string sql, object values); /// - /// Выборка данных из таблицы + /// Запрос /// - /// Тип данных - /// Имя таблицы - /// Выбор столбцов таблицы, которые должны попасть в выборку (пустая -- все) - /// Массив значений столбцов, которые должны попасть в выборку - /// Сортировка - /// Сколько максимально элементов должно быть в выборке (0 -- без ограничения) - /// Массив типа - Task> SelectAsync (string table, string[] columns, List> where, string? orderBy, int limit = 0); + /// Тип передаваемого значения + /// Запрос + /// Данные запроса + /// Возвращает массив типа или значение по умолчанию + IEnumerable Query (string sql, object values); /// - /// Выборка строки из таблицы + /// Запрос строки /// - /// Тип данных - /// Имя таблицы - /// Выбор столбцов таблицы, которые должны попасть в выборку (пустая -- все) - /// Массив значений столбцов, которые должны попасть в выборку - /// Сортировка - /// Тип или null - Task SelectRowAsync (string table, string[] columns, List> where, string? orderBy = null); - #endregion + /// Тип передаваемого значения + /// Запрос + /// Данные запроса + /// Возвращает массив типа или значение по умолчанию + Task QueryRowAsync (string sql, object values); - #region Вычисление числа элементов в таблице /// - /// Вычисляет число строк в таблице + /// Запрос строки /// - /// Таблица - /// Число строк в таблице - Task CountAsync (string table); + /// Тип передаваемого значения + /// Запрос + /// Данные запроса + /// Возвращает массив типа или значение по умолчанию + T? QueryRow (string sql, object values); #endregion - #region Добавление строки в таблицу + #region Получение данных - Task InsertAsync (string table, T entity, KeyValue primaryIndex); + /// + /// Получает массив данных (SELECT * FROM...) + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Массив результата запроса + Task> GetResultsAsync (string sql, object values); - Task InsertUpdateAsync (string table, T entity); + /// + /// Получает массив данных (SELECT * FROM...) + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Массив результата запроса + IEnumerable GetResults (string sql, object values); + + /// + /// Получает строку в массиве данных + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Строки данных или null + Task GetRowAsync (string sql, object values); + + /// + /// Получает строку в массиве данных + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Строки данных или null + T? GetRow (string sql, object values); + + /// + /// Получает колонку в массиве данных + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Колонка данных или null + Task> GetColAsync (string sql, object values) where T : IComparable, IConvertible, IEquatable; + + /// + /// Получает колонку в массиве данных + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Колонка данных или null + IEnumerable GetCol (string sql, object values) where T : IComparable, IConvertible, IEquatable; + + /// + /// Получение значение единичного поля + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Поле или null + Task GetVarAsync (string sql, object values) where T : IComparable, IConvertible, IEquatable; + + /// + /// Получение значение единичного поля + /// + /// Тип получаемых данных + /// SQL-запрос + /// Данные запроса + /// Поле или null + T? GetVar (string sql, object values) where T : IComparable, IConvertible, IEquatable; #endregion - #region Обновление строки в таблице + #region CRUD данные + /// + /// Вставляет данные в таблицу + /// + /// Класс данных + /// Данные + /// Имя таблицы + /// Результат выполнения + Task InsertAsync (T data, string tableName) where T : class; - Task UpdateAsync (string table, T entity, KeyValue where); + /// + /// Вставляет данные в таблицу + /// + /// Класс данных + /// Данные + /// Имя таблицы + /// Результат выполнения + bool Insert (T data, string tableName) where T : class; - #endregion + /// + /// Обновляет строку в таблице + /// + /// Класс данных + /// Данные + /// Имя таблицы + /// Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data + /// Результат выполнения + Task UpdateAsync (T data, string tableName, string whereConditionColumn) where T : class; - #region Удаление строк + /// + /// Обновляет строку в таблице + /// + /// Класс данных + /// Данные + /// Имя таблицы + /// Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data + /// Результат выполнения + bool Update (T data, string tableName, string whereConditionColumn) where T : class; - Task DeleteAsync (string table, KeyValue where); + /// + /// Удаляет строки + /// + /// Имя таблицы + /// Условие + /// Результат выполнения + Task DeleteAsync (string tableName, KeyValue where); - Task DeleteRowAsync (string table, KeyValue where); + /// + /// Удаляет строки + /// + /// Имя таблицы + /// Условие + /// Результат выполнения + bool Delete (string tableName, KeyValue where); + /// + /// Удаляет строку + /// + /// Имя таблицы + /// Условие + /// Результат выполнения + Task DeleteRowAsync (string tableName, KeyValue where); + + /// + /// Удаляет строку + /// + /// Имя таблицы + /// Условие + /// Результат выполнения + bool DeleteRow (string tableName, KeyValue where); #endregion } \ No newline at end of file diff --git a/anbs_cpdb/anbs_cpdb.csproj b/anbs_cpdb/anbs_cpdb.csproj index fd807b8..a96949b 100644 --- a/anbs_cpdb/anbs_cpdb.csproj +++ b/anbs_cpdb/anbs_cpdb.csproj @@ -8,7 +8,7 @@ anbs_cp.Database True ANBSoftware.ComponentsPack.Database - 2023.08.18 + 2023.08.19 Александр Бабаев Набор компонентов ANB Software для работы с БД Библиотека полезных методов языка C# для работы с базами данных @@ -22,6 +22,7 @@ +