diff --git a/FunGame.Server/FunGame.Server.csproj b/FunGame.Server/FunGame.Server.csproj index d2b577e..cdd46ea 100644 --- a/FunGame.Server/FunGame.Server.csproj +++ b/FunGame.Server/FunGame.Server.csproj @@ -47,6 +47,7 @@ + diff --git a/FunGame.Server/Services/DataUtility/MySQLHelper.cs b/FunGame.Server/Services/DataUtility/MySQLHelper.cs index 54efb97..773bd62 100644 --- a/FunGame.Server/Services/DataUtility/MySQLHelper.cs +++ b/FunGame.Server/Services/DataUtility/MySQLHelper.cs @@ -1,4 +1,5 @@ using System.Data; +using System.Data.Common; using Milimoe.FunGame.Core.Api.Transmittal; using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Model; @@ -9,14 +10,59 @@ namespace Milimoe.FunGame.Server.Services.DataUtility { public class MySQLHelper : SQLHelper { + /// + /// FunGame 类型 + /// public override FunGameInfo.FunGame FunGameType { get; } = FunGameInfo.FunGame.FunGame_Server; + + /// + /// 使用的数据库类型 + /// public override SQLMode Mode { get; } = SQLMode.MySQL; + + /// + /// SQL 脚本 + /// public override string Script { get; set; } = ""; + + /// + /// 命令类型 + /// public override CommandType CommandType { get; set; } = CommandType.Text; + + /// + /// 数据库事务 + /// + public override DbTransaction? Transaction => _transaction; + + /// + /// 执行结果 + /// public override SQLResult Result => _result; + + /// + /// SQL 服务器信息 + /// public override SQLServerInfo ServerInfo => _serverInfo ?? SQLServerInfo.Create(); - public override int UpdateRows => _updateRows; + + /// + /// 上一次执行命令影响的行数 + /// + public override int AffectedRows => _affectedRows; + + /// + /// 上一次执行的命令是 Insert 时,返回的自增 ID,大于 0 有效 + /// + public override long LastInsertId => _lastInsertId; + + /// + /// 上一次执行命令的查询结果集 + /// public override DataSet DataSet => _dataSet; + + /// + /// SQL 语句参数 + /// public override Dictionary Parameters { get; } = []; private readonly string _connectionString = ""; @@ -25,7 +71,8 @@ namespace Milimoe.FunGame.Server.Services.DataUtility private DataSet _dataSet = new(); private SQLResult _result = SQLResult.NotFound; private readonly SQLServerInfo? _serverInfo; - private int _updateRows = 0; + private int _affectedRows = 0; + private long _lastInsertId = 0; public MySQLHelper(string script = "", CommandType type = CommandType.Text) { @@ -69,7 +116,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } /// - /// 执行一个命令 + /// 执行现有命令() /// /// public override int Execute() @@ -104,14 +151,24 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } if (_transaction != null) command.Transaction = _transaction; - _updateRows = command.ExecuteNonQuery(); - _result = SQLResult.Success; + ReSet(); + _affectedRows = command.ExecuteNonQuery(); + if (_affectedRows > 0) + { + _result = SQLResult.Success; + if (script.Contains(Core.Library.SQLScript.Constant.Command_Insert, StringComparison.OrdinalIgnoreCase)) + { + _lastInsertId = command.LastInsertedId; + if (_lastInsertId < 0) _lastInsertId = 0; + } + } + else _result = SQLResult.Fail; if (localTransaction) Commit(); } catch (Exception e) { if (localTransaction) Rollback(); - _result = SQLResult.Fail; + _result = SQLResult.SQLError; ServerHelper.Error(e); } finally @@ -119,11 +176,75 @@ namespace Milimoe.FunGame.Server.Services.DataUtility if (localTransaction) Close(); if (ClearParametersAfterExecute) Parameters.Clear(); } - return UpdateRows; + return AffectedRows; } /// - /// 查询DataSet + /// 异步执行现有命令() + /// + /// + public override async Task ExecuteAsync() + { + return await ExecuteAsync(Script); + } + + /// + /// 异步执行一个指定的命令 + /// + /// + /// + public override async Task ExecuteAsync(string script) + { + bool localTransaction = _transaction == null; + + try + { + if (localTransaction) + { + NewTransaction(); + } + + OpenConnection(); + Script = script; + ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api); + using MySqlCommand command = new(script, _connection); + command.CommandType = CommandType; + foreach (KeyValuePair param in Parameters) + { + command.Parameters.AddWithValue(param.Key, param.Value); + } + if (_transaction != null) command.Transaction = _transaction; + + ReSet(); + _affectedRows = await command.ExecuteNonQueryAsync(); + if (_affectedRows > 0) + { + _result = SQLResult.Success; + if (script.Contains(Core.Library.SQLScript.Constant.Command_Insert, StringComparison.OrdinalIgnoreCase)) + { + _lastInsertId = command.LastInsertedId; + if (_lastInsertId < 0) _lastInsertId = 0; + } + } + else _result = SQLResult.Fail; + if (localTransaction) Commit(); + } + catch (Exception e) + { + if (localTransaction) Rollback(); + _result = SQLResult.SQLError; + ServerHelper.Error(e); + } + finally + { + if (localTransaction) Close(); + if (ClearParametersAfterExecute) Parameters.Clear(); + } + return AffectedRows; + } + + /// + /// 执行现有命令()查询 DataSet /// /// public override DataSet ExecuteDataSet() @@ -132,7 +253,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } /// - /// 执行指定的命令查询DataSet + /// 执行指定的命令查询 DataSet /// /// /// @@ -161,12 +282,13 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } if (_transaction != null) command.Transaction = _transaction; + ReSet(); MySqlDataAdapter adapter = new() { SelectCommand = command }; _dataSet = new(); - adapter.Fill(_dataSet); + _affectedRows = adapter.Fill(_dataSet); if (localTransaction) Commit(); @@ -175,7 +297,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility catch (Exception e) { if (localTransaction) Rollback(); - _result = SQLResult.Fail; + _result = SQLResult.SQLError; ServerHelper.Error(e); } finally @@ -187,26 +309,68 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } /// - /// 检查数据库是否存在 + /// 异步执行现有命令()查询 DataSet /// /// - public override bool DatabaseExists() + public override async Task ExecuteDataSetAsync() { + return await ExecuteDataSetAsync(Script); + } + + /// + /// 异步执行指定的命令查询 DataSet + /// + /// + /// + public override async Task ExecuteDataSetAsync(string script) + { + bool localTransaction = _transaction == null; + try { - ExecuteDataSet(Core.Library.SQLScript.Common.Configs.Select_GetConfig(this, "Initialization")); - return Success; + if (localTransaction) + { + NewTransaction(); + } + + OpenConnection(); + Script = script; + ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api); + + using MySqlCommand command = new(script, _connection) + { + CommandType = CommandType + }; + foreach (KeyValuePair param in Parameters) + { + command.Parameters.AddWithValue(param.Key, param.Value); + } + if (_transaction != null) command.Transaction = _transaction; + + ReSet(); + MySqlDataAdapter adapter = new() + { + SelectCommand = command + }; + _dataSet = new(); + _affectedRows = await adapter.FillAsync(_dataSet); + + if (localTransaction) Commit(); + + _result = _dataSet.Tables.Cast().Any(table => table.Rows.Count > 0) ? SQLResult.Success : SQLResult.NotFound; } catch (Exception e) { + if (localTransaction) Rollback(); + _result = SQLResult.SQLError; ServerHelper.Error(e); - _result = SQLResult.Fail; - return false; } finally { - Close(); + if (localTransaction) Close(); + if (ClearParametersAfterExecute) Parameters.Clear(); } + return _dataSet; } /// @@ -233,7 +397,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } catch (Exception e) { - _result = SQLResult.Fail; + _result = SQLResult.SQLError; ServerHelper.Error(e); } finally @@ -254,7 +418,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } catch (Exception e) { - _result = SQLResult.Fail; + _result = SQLResult.SQLError; ServerHelper.Error(e); } finally @@ -263,12 +427,35 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } } + /// + /// 检查数据库是否存在 + /// + /// + public override bool DatabaseExists() + { + try + { + ExecuteDataSet(Core.Library.SQLScript.Common.Configs.Select_GetConfig(this, "Initialization")); + return Success; + } + catch (Exception e) + { + ServerHelper.Error(e); + _result = SQLResult.SQLError; + return false; + } + finally + { + Close(); + } + } + private bool _isDisposed = false; /// /// 资源清理 /// - public void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!_isDisposed) { @@ -289,5 +476,13 @@ namespace Milimoe.FunGame.Server.Services.DataUtility Dispose(true); GC.SuppressFinalize(this); } + + private void ReSet() + { + _result = SQLResult.NotFound; + _affectedRows = 0; + _lastInsertId = 0; + DataSet.Clear(); + } } } diff --git a/FunGame.Server/Services/DataUtility/SQLiteHelper.cs b/FunGame.Server/Services/DataUtility/SQLiteHelper.cs index 57cce4f..510d396 100644 --- a/FunGame.Server/Services/DataUtility/SQLiteHelper.cs +++ b/FunGame.Server/Services/DataUtility/SQLiteHelper.cs @@ -1,4 +1,5 @@ using System.Data; +using System.Data.Common; using Microsoft.Data.Sqlite; using Milimoe.FunGame.Core.Api.Transmittal; using Milimoe.FunGame.Core.Library.Constant; @@ -9,14 +10,59 @@ namespace Milimoe.FunGame.Server.Services.DataUtility { public class SQLiteHelper : SQLHelper { + /// + /// FunGame 类型 + /// public override FunGameInfo.FunGame FunGameType { get; } = FunGameInfo.FunGame.FunGame_Server; + + /// + /// 使用的数据库类型 + /// public override SQLMode Mode { get; } = SQLMode.SQLite; + + /// + /// SQL 脚本 + /// public override string Script { get; set; } = ""; + + /// + /// 命令类型 + /// public override CommandType CommandType { get; set; } = CommandType.Text; + + /// + /// 数据库事务 + /// + public override DbTransaction? Transaction => _transaction; + + /// + /// 执行结果 + /// public override SQLResult Result => _result; + + /// + /// SQL 服务器信息 + /// public override SQLServerInfo ServerInfo => _serverInfo ?? SQLServerInfo.Create(); - public override int UpdateRows => _updateRows; + + /// + /// 上一次执行命令影响的行数 + /// + public override int AffectedRows => _affectedRows; + + /// + /// 上一次执行的命令是 Insert 时,返回的自增 ID,大于 0 有效 + /// + public override long LastInsertId => _lastInsertId; + + /// + /// 上一次执行命令的查询结果集 + /// public override DataSet DataSet => _dataSet; + + /// + /// SQL 语句参数 + /// public override Dictionary Parameters { get; } = []; private readonly string _connectionString = ""; @@ -25,7 +71,8 @@ namespace Milimoe.FunGame.Server.Services.DataUtility private DataSet _dataSet = new(); private SQLResult _result = SQLResult.NotFound; private readonly SQLServerInfo? _serverInfo; - private int _updateRows = 0; + private int _affectedRows = 0; + private long _lastInsertId = 0; public SQLiteHelper(string script = "", CommandType type = CommandType.Text) { @@ -67,7 +114,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } /// - /// 执行一个命令 + /// 执行现有命令() /// /// public override int Execute() @@ -102,14 +149,26 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } if (_transaction != null) command.Transaction = _transaction; - _updateRows = command.ExecuteNonQuery(); - _result = SQLResult.Success; + ReSet(); + _affectedRows = command.ExecuteNonQuery(); + if (_affectedRows > 0) + { + _result = SQLResult.Success; + if (script.Contains(Core.Library.SQLScript.Constant.Command_Insert, StringComparison.OrdinalIgnoreCase)) + { + using SqliteCommand idCommand = new("SELECT last_insert_rowid()", _connection); + if (_transaction != null) idCommand.Transaction = _transaction; + _lastInsertId = (long?)idCommand.ExecuteScalar() ?? 0; + if (_lastInsertId < 0) _lastInsertId = 0; + } + } + else _result = SQLResult.Fail; if (localTransaction) Commit(); } catch (Exception e) { if (localTransaction) Rollback(); - _result = SQLResult.Fail; + _result = SQLResult.SQLError; ServerHelper.Error(e); } finally @@ -117,11 +176,77 @@ namespace Milimoe.FunGame.Server.Services.DataUtility if (localTransaction) Close(); if (ClearParametersAfterExecute) Parameters.Clear(); } - return UpdateRows; + return AffectedRows; } /// - /// 查询DataSet + /// 异步执行现有命令() + /// + /// + public override async Task ExecuteAsync() + { + return await ExecuteAsync(Script); + } + + /// + /// 异步执行一个指定的命令 + /// + /// + /// + public override async Task ExecuteAsync(string script) + { + bool localTransaction = _transaction == null; + + try + { + if (localTransaction) + { + NewTransaction(); + } + + OpenConnection(); + Script = script; + ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api); + using SqliteCommand command = new(script, _connection); + command.CommandType = CommandType; + foreach (KeyValuePair param in Parameters) + { + command.Parameters.AddWithValue(param.Key, param.Value); + } + if (_transaction != null) command.Transaction = _transaction; + + ReSet(); + _affectedRows = await command.ExecuteNonQueryAsync(); + if (_affectedRows > 0) + { + _result = SQLResult.Success; + if (script.Contains(Core.Library.SQLScript.Constant.Command_Insert, StringComparison.OrdinalIgnoreCase)) + { + using SqliteCommand idCommand = new("SELECT last_insert_rowid()", _connection); + if (_transaction != null) idCommand.Transaction = _transaction; + _lastInsertId = (long?)await idCommand.ExecuteScalarAsync() ?? 0; + if (_lastInsertId < 0) _lastInsertId = 0; + } + } + else _result = SQLResult.Fail; + if (localTransaction) Commit(); + } + catch (Exception e) + { + if (localTransaction) Rollback(); + _result = SQLResult.SQLError; + ServerHelper.Error(e); + } + finally + { + if (localTransaction) Close(); + if (ClearParametersAfterExecute) Parameters.Clear(); + } + return AffectedRows; + } + + /// + /// 执行现有命令()查询 DataSet /// /// public override DataSet ExecuteDataSet() @@ -130,7 +255,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } /// - /// 执行指定的命令查询DataSet + /// 执行指定的命令查询 DataSet /// /// /// @@ -158,6 +283,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } if (_transaction != null) command.Transaction = _transaction; + ReSet(); using SqliteDataReader reader = command.ExecuteReader(); _dataSet = new(); do @@ -174,7 +300,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility catch (Exception e) { if (localTransaction) Rollback(); - _result = SQLResult.Fail; + _result = SQLResult.SQLError; ServerHelper.Error(e); } finally @@ -186,7 +312,73 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } /// - /// 创建一个SQL事务 + /// 异步执行现有命令()查询 DataSet + /// + /// + public override async Task ExecuteDataSetAsync() + { + return await ExecuteDataSetAsync(Script); + } + + /// + /// 异步执行指定的命令查询 DataSet + /// + /// + /// + public override async Task ExecuteDataSetAsync(string script) + { + bool localTransaction = _transaction == null; + + try + { + if (localTransaction) + { + NewTransaction(); + } + + OpenConnection(); + Script = script; + ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api); + using SqliteCommand command = new(script, _connection) + { + CommandType = CommandType + }; + foreach (KeyValuePair param in Parameters) + { + command.Parameters.AddWithValue(param.Key, param.Value); + } + if (_transaction != null) command.Transaction = _transaction; + + ReSet(); + using SqliteDataReader reader = await command.ExecuteReaderAsync(); + _dataSet = new(); + do + { + DataTable table = new(); + table.Load(reader); + _dataSet.Tables.Add(table); + } while (!reader.IsClosed && reader.NextResult()); + + if (localTransaction) Commit(); + + _result = _dataSet.Tables.Cast().Any(table => table.Rows.Count > 0) ? SQLResult.Success : SQLResult.NotFound; + } + catch (Exception e) + { + if (localTransaction) Rollback(); + _result = SQLResult.SQLError; + ServerHelper.Error(e); + } + finally + { + if (localTransaction) Close(); + if (ClearParametersAfterExecute) Parameters.Clear(); + } + return _dataSet; + } + + /// + /// 创建一个 SQL 事务 /// public override void NewTransaction() { @@ -209,7 +401,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } catch (Exception e) { - _result = SQLResult.Fail; + _result = SQLResult.SQLError; ServerHelper.Error(e); } finally @@ -230,7 +422,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility } catch (Exception e) { - _result = SQLResult.Fail; + _result = SQLResult.SQLError; ServerHelper.Error(e); } finally @@ -253,7 +445,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility catch (Exception e) { ServerHelper.Error(e); - _result = SQLResult.Fail; + _result = SQLResult.SQLError; return false; } finally @@ -267,7 +459,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility /// /// 资源清理 /// - public void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!_isDisposed) { @@ -288,5 +480,13 @@ namespace Milimoe.FunGame.Server.Services.DataUtility Dispose(true); GC.SuppressFinalize(this); } + + private void ReSet() + { + _result = SQLResult.NotFound; + _affectedRows = 0; + _lastInsertId = 0; + DataSet.Clear(); + } } } diff --git a/FunGame.WebAPI/FunGame.WebAPI.csproj b/FunGame.WebAPI/FunGame.WebAPI.csproj index e86a67e..91a9462 100644 --- a/FunGame.WebAPI/FunGame.WebAPI.csproj +++ b/FunGame.WebAPI/FunGame.WebAPI.csproj @@ -32,6 +32,7 @@ + diff --git a/FunGameServer.sln b/FunGameServer.sln index f7c0a2f..d00eaac 100644 --- a/FunGameServer.sln +++ b/FunGameServer.sln @@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunGame.WebAPI", "FunGame.W EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunGame.Core", "..\FunGame.Core\FunGame.Core.csproj", "{33CAC80F-8394-41DB-B5AF-5E91123E6C84}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunGame.SQLQueryExtension", "..\FunGame.Extension\FunGame.SQLQueryExtension\FunGame.SQLQueryExtension.csproj", "{9EEB3474-B9A1-4E5E-BEF0-14F30D81873C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +35,10 @@ Global {33CAC80F-8394-41DB-B5AF-5E91123E6C84}.Debug|Any CPU.Build.0 = Debug|Any CPU {33CAC80F-8394-41DB-B5AF-5E91123E6C84}.Release|Any CPU.ActiveCfg = Release|Any CPU {33CAC80F-8394-41DB-B5AF-5E91123E6C84}.Release|Any CPU.Build.0 = Release|Any CPU + {9EEB3474-B9A1-4E5E-BEF0-14F30D81873C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9EEB3474-B9A1-4E5E-BEF0-14F30D81873C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9EEB3474-B9A1-4E5E-BEF0-14F30D81873C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9EEB3474-B9A1-4E5E-BEF0-14F30D81873C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE