啊鑫
2025-07-22 038587a4ff652278fe22c2d03c1ebb602b95c5f0
Database/DatabaseManager.cs
@@ -1,6 +1,7 @@
using GSModbus.Config;
using SqlSugar;
using System.Text.Json;
using Oracle.ManagedDataAccess.Client;
namespace GSModbus.Database
{
@@ -78,40 +79,16 @@
        {
            try
            {
                // 根据数据库类型创建SqlSugarClient
                var dbType = GetDbType(_config.Type);
                OnDatabaseLog("开始初始化数据库连接...");
                
                _db = new SqlSugarClient(new SqlSugar.ConnectionConfig()
                // 对Oracle特殊处理,避免SqlSugar语法问题
                if (_config.Type.ToLower() == "oracle")
                {
                    ConnectionString = _config.ConnectionString,
                    DbType = dbType,
                    IsAutoCloseConnection = true,
                    // 配置SQL日志
                    MoreSettings = new ConnMoreSettings()
                    {
                        IsAutoRemoveDataCache = true
                    }
                });
                // 配置日志事件
                _db.Aop.OnLogExecuting = (sql, pars) =>
                    InitializeOracleDirectly();
                }
                else
                {
                    OnDatabaseLog($"执行SQL: {sql}");
                    if (pars?.Any() == true)
                    {
                        OnDatabaseLog($"参数: {string.Join(", ", pars.Select(p => $"{p.ParameterName}={p.Value}"))}");
                    }
                };
                // 测试连接
                var version = _db.Ado.GetString("SELECT @@VERSION");
                OnDatabaseLog($"数据库连接成功,版本: {version?.Substring(0, Math.Min(version.Length, 50))}...");
                // 自动创建表
                if (_config.AutoCreateTables)
                {
                    CreateTablesIfNotExists();
                    InitializeWithSqlSugar();
                }
                OnDatabaseLog("数据库管理器初始化完成");
@@ -120,6 +97,93 @@
            {
                OnDatabaseError($"初始化数据库失败: {ex.Message}");
                throw;
            }
        }
        /// <summary>
        /// 直接初始化Oracle数据库
        /// </summary>
        private void InitializeOracleDirectly()
        {
            try
            {
                OnDatabaseLog("使用Oracle原生方式初始化...");
                // 先测试连接
                using (var testConnection = new OracleConnection(_config.ConnectionString))
                {
                    testConnection.Open();
                    OnDatabaseLog("Oracle数据库连接测试成功");
                    testConnection.Close();
                }
                // 创建SqlSugar客户端(只用于数据操作,不用于连接测试)
                var dbType = GetDbType(_config.Type);
                _db = new SqlSugarClient(new SqlSugar.ConnectionConfig()
                {
                    ConnectionString = _config.ConnectionString,
                    DbType = dbType,
                    IsAutoCloseConnection = true,
                    MoreSettings = new ConnMoreSettings()
                    {
                        IsAutoRemoveDataCache = true
                    }
                });
                OnDatabaseLog("SqlSugar客户端创建成功");
                // 自动创建表(使用直接SQL方式)
                if (_config.AutoCreateTables)
                {
                    CreateTablesIfNotExists();
                }
            }
            catch (Exception ex)
            {
                OnDatabaseError($"Oracle数据库初始化失败: {ex.Message}");
                throw;
            }
        }
        /// <summary>
        /// 使用SqlSugar初始化其他数据库
        /// </summary>
        private void InitializeWithSqlSugar()
        {
            // 根据数据库类型创建SqlSugarClient
            var dbType = GetDbType(_config.Type);
            _db = new SqlSugarClient(new SqlSugar.ConnectionConfig()
            {
                ConnectionString = _config.ConnectionString,
                DbType = dbType,
                IsAutoCloseConnection = true,
                // 配置SQL日志
                MoreSettings = new ConnMoreSettings()
                {
                    IsAutoRemoveDataCache = true
                }
            });
            // 配置日志事件
            _db.Aop.OnLogExecuting = (sql, pars) =>
            {
                OnDatabaseLog($"执行SQL: {sql}");
                if (pars?.Any() == true)
                {
                    OnDatabaseLog($"参数: {string.Join(", ", pars.Select(p => $"{p.ParameterName}={p.Value}"))}");
                }
            };
            // 测试连接
            var version = _db.Ado.GetString("SELECT @@VERSION");
            OnDatabaseLog($"数据库连接成功,版本: {version?.Substring(0, Math.Min(version.Length, 50))}...");
            // 自动创建表
            if (_config.AutoCreateTables)
            {
                CreateTablesIfNotExists();
            }
        }
@@ -150,27 +214,173 @@
            {
                OnDatabaseLog("开始检查和创建数据库表...");
                // 创建ModbusData表
                _db.CodeFirst.SetStringDefaultLength(200).InitTables(typeof(ModbusDataEntity));
                OnDatabaseLog($"ModbusData表检查完成,表名: {_config.Tables.ModbusDataTable}");
                // 对Oracle使用直接SQL建表,避免SqlSugar语法问题
                if (GetDbType(_config.Type) == DbType.Oracle)
                {
                    CreateOracleTablesDirectly();
                }
                else
                {
                    // 其他数据库使用SqlSugar CodeFirst
                    _db.CodeFirst.SetStringDefaultLength(200).InitTables(typeof(ModbusDataEntity));
                    OnDatabaseLog($"ModbusData表检查完成,表名: {_config.Tables.ModbusDataTable}");
                // 创建CommunicationLog表
                _db.CodeFirst.SetStringDefaultLength(200).InitTables(typeof(CommunicationLogEntity));
                OnDatabaseLog($"CommunicationLog表检查完成,表名: {_config.Tables.CommunicationLogTable}");
                    _db.CodeFirst.SetStringDefaultLength(200).InitTables(typeof(CommunicationLogEntity));
                    OnDatabaseLog($"CommunicationLog表检查完成,表名: {_config.Tables.CommunicationLogTable}");
                // 创建ErrorLog表
                _db.CodeFirst.SetStringDefaultLength(200).InitTables(typeof(ErrorLogEntity));
                OnDatabaseLog($"ErrorLog表检查完成,表名: {_config.Tables.ErrorLogTable}");
                    _db.CodeFirst.SetStringDefaultLength(200).InitTables(typeof(ErrorLogEntity));
                    OnDatabaseLog($"ErrorLog表检查完成,表名: {_config.Tables.ErrorLogTable}");
                // 创建Statistics表
                _db.CodeFirst.SetStringDefaultLength(200).InitTables(typeof(StatisticsEntity));
                OnDatabaseLog($"Statistics表检查完成,表名: {_config.Tables.StatisticsTable}");
                    _db.CodeFirst.SetStringDefaultLength(200).InitTables(typeof(StatisticsEntity));
                    OnDatabaseLog($"Statistics表检查完成,表名: {_config.Tables.StatisticsTable}");
                }
                OnDatabaseLog("所有数据库表检查完成");
            }
            catch (Exception ex)
            {
                OnDatabaseError($"创建数据库表失败: {ex.Message}");
                throw;
            }
        }
        /// <summary>
        /// 直接使用SQL为Oracle创建表
        /// </summary>
        private void CreateOracleTablesDirectly()
        {
            try
            {
                OnDatabaseLog("开始使用原生Oracle SQL创建表...");
                using (var connection = new OracleConnection(_config.ConnectionString))
                {
                    connection.Open();
                    OnDatabaseLog("Oracle连接已打开,开始执行建表脚本...");
                    // 1. 创建ModbusData表(主要数据表)
                    var createModbusDataTable = $@"
                        BEGIN
                            EXECUTE IMMEDIATE 'CREATE TABLE {_config.Tables.ModbusDataTable} (
                                ID NUMBER PRIMARY KEY,
                                READ_TIME TIMESTAMP NOT NULL,
                                PROJECT_NAME VARCHAR2(100) NOT NULL,
                                PLC_IP_ADDRESS VARCHAR2(50) NOT NULL,
                                CONTROL_SIGNALS_JSON CLOB,
                                PRODUCT_DATA_JSON CLOB,
                                MEASUREMENT_DATA_JSON CLOB,
                                RAW_REGISTERS_JSON CLOB,
                                CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
                            )';
                        EXCEPTION
                            WHEN OTHERS THEN
                                IF SQLCODE != -955 THEN -- -955 = table already exists
                                    RAISE;
                                END IF;
                        END;";
                    using (var cmd = new OracleCommand(createModbusDataTable, connection))
                    {
                        cmd.ExecuteNonQuery();
                    }
                    OnDatabaseLog($"ModbusData表检查完成,表名: {_config.Tables.ModbusDataTable}");
                    // 2. 创建CommunicationLog表
                    var createCommLogTable = $@"
                        BEGIN
                            EXECUTE IMMEDIATE 'CREATE TABLE {_config.Tables.CommunicationLogTable} (
                                ID NUMBER PRIMARY KEY,
                                LOG_TIME TIMESTAMP NOT NULL,
                                PROJECT_NAME VARCHAR2(100) NOT NULL,
                                PLC_IP_ADDRESS VARCHAR2(50) NOT NULL,
                                EVENT_TYPE VARCHAR2(50) NOT NULL,
                                EVENT_DESCRIPTION VARCHAR2(500),
                                IS_SUCCESS NUMBER(1) DEFAULT 1,
                                DURATION_MS NUMBER,
                                ADDITIONAL_DATA_JSON CLOB
                            )';
                        EXCEPTION
                            WHEN OTHERS THEN
                                IF SQLCODE != -955 THEN
                                    RAISE;
                                END IF;
                        END;";
                    using (var cmd = new OracleCommand(createCommLogTable, connection))
                    {
                        cmd.ExecuteNonQuery();
                    }
                    OnDatabaseLog($"CommunicationLog表检查完成,表名: {_config.Tables.CommunicationLogTable}");
                    // 3. 创建ErrorLog表
                    var createErrorLogTable = $@"
                        BEGIN
                            EXECUTE IMMEDIATE 'CREATE TABLE {_config.Tables.ErrorLogTable} (
                                ID NUMBER PRIMARY KEY,
                                ERROR_TIME TIMESTAMP NOT NULL,
                                PROJECT_NAME VARCHAR2(100) NOT NULL,
                                PLC_IP_ADDRESS VARCHAR2(50) NOT NULL,
                                ERROR_TYPE VARCHAR2(100) NOT NULL,
                                ERROR_MESSAGE VARCHAR2(1000) NOT NULL,
                                STACK_TRACE CLOB,
                                SEVERITY VARCHAR2(20) DEFAULT ''Medium'',
                                RETRY_COUNT NUMBER DEFAULT 0,
                                IS_RESOLVED NUMBER(1) DEFAULT 0
                            )';
                        EXCEPTION
                            WHEN OTHERS THEN
                                IF SQLCODE != -955 THEN
                                    RAISE;
                                END IF;
                        END;";
                    using (var cmd = new OracleCommand(createErrorLogTable, connection))
                    {
                        cmd.ExecuteNonQuery();
                    }
                    OnDatabaseLog($"ErrorLog表检查完成,表名: {_config.Tables.ErrorLogTable}");
                    // 4. 创建Statistics表
                    var createStatsTable = $@"
                        BEGIN
                            EXECUTE IMMEDIATE 'CREATE TABLE {_config.Tables.StatisticsTable} (
                                ID NUMBER PRIMARY KEY,
                                STATISTICS_TIME TIMESTAMP NOT NULL,
                                PROJECT_NAME VARCHAR2(100) NOT NULL,
                                PLC_IP_ADDRESS VARCHAR2(50) NOT NULL,
                                TOTAL_CONNECTION_ATTEMPTS NUMBER NOT NULL,
                                SUCCESSFUL_CONNECTIONS NUMBER NOT NULL,
                                TOTAL_DATA_READS NUMBER NOT NULL,
                                SUCCESSFUL_DATA_READS NUMBER NOT NULL,
                                TOTAL_ERRORS NUMBER NOT NULL,
                                AVERAGE_RESPONSE_TIME_MS NUMBER NOT NULL,
                                MAX_RESPONSE_TIME_MS NUMBER NOT NULL,
                                MIN_RESPONSE_TIME_MS NUMBER NOT NULL,
                                CONNECTION_SUCCESS_RATE NUMBER NOT NULL,
                                DATA_READ_SUCCESS_RATE NUMBER NOT NULL,
                                PERIOD_START TIMESTAMP NOT NULL,
                                PERIOD_END TIMESTAMP NOT NULL
                            )';
                        EXCEPTION
                            WHEN OTHERS THEN
                                IF SQLCODE != -955 THEN
                                    RAISE;
                                END IF;
                        END;";
                    using (var cmd = new OracleCommand(createStatsTable, connection))
                    {
                        cmd.ExecuteNonQuery();
                    }
                    OnDatabaseLog($"Statistics表检查完成,表名: {_config.Tables.StatisticsTable}");
                    connection.Close();
                    OnDatabaseLog("所有Oracle表创建完成,连接已关闭");
                }
            }
            catch (Exception ex)
            {
                OnDatabaseError($"Oracle建表失败: {ex.Message}");
                throw;
            }
        }
@@ -507,6 +717,164 @@
        #endregion
        #region 连接测试方法
        /// <summary>
        /// 测试数据库连接
        /// </summary>
        /// <returns>连接测试结果</returns>
        public async Task<(bool Success, string Message)> TestConnectionAsync()
        {
            try
            {
                if (!_config.Enabled)
                {
                    return (false, "数据库功能已禁用");
                }
                if (string.IsNullOrEmpty(_config.ConnectionString))
                {
                    return (false, "数据库连接字符串为空");
                }
                // 对于Oracle数据库,使用原生连接方式测试
                if (_config.Type.ToLower() == "oracle")
                {
                    return await TestOracleConnectionAsync();
                }
                // 创建临时连接进行测试
                var dbType = GetDbType(_config.Type);
                using var testDb = new SqlSugarClient(new SqlSugar.ConnectionConfig()
                {
                    ConnectionString = _config.ConnectionString,
                    DbType = dbType,
                    IsAutoCloseConnection = true
                });
                // 执行简单查询测试连接
                string testQuery = dbType switch
                {
                    DbType.SqlServer => "SELECT 1",
                    DbType.MySql => "SELECT 1",
                    DbType.Sqlite => "SELECT 1",
                    DbType.PostgreSQL => "SELECT 1",
                    _ => "SELECT 1"
                };
                var result = await testDb.Ado.GetScalarAsync(testQuery);
                if (result != null)
                {
                    return (true, $"连接成功!数据库类型: {_config.Type}");
                }
                else
                {
                    return (false, "连接测试查询返回空结果");
                }
            }
            catch (Exception ex)
            {
                return (false, $"连接失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 测试Oracle数据库连接的专用方法
        /// </summary>
        private async Task<(bool Success, string Message)> TestOracleConnectionAsync()
        {
            try
            {
                using var connection = new Oracle.ManagedDataAccess.Client.OracleConnection(_config.ConnectionString);
                await connection.OpenAsync();
                using var command = connection.CreateCommand();
                command.CommandText = "SELECT SYSDATE FROM DUAL";
                var result = await command.ExecuteScalarAsync();
                if (result != null)
                {
                    await connection.CloseAsync();
                    return (true, $"Oracle连接成功!当前时间: {result}");
                }
                else
                {
                    return (false, "Oracle连接测试查询返回空结果");
                }
            }
            catch (Exception ex)
            {
                return (false, $"Oracle连接失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 静态方法:测试数据库连接(用于配置验证)
        /// </summary>
        /// <param name="config">数据库配置</param>
        /// <returns>连接测试结果</returns>
        public static async Task<(bool Success, string Message)> TestConnectionAsync(DatabaseConfig config)
        {
            if (config == null)
            {
                return (false, "数据库配置为空");
            }
            if (!config.Enabled)
            {
                return (false, "数据库功能已禁用");
            }
            if (string.IsNullOrEmpty(config.ConnectionString))
            {
                return (false, "数据库连接字符串为空");
            }
            try
            {
                // 对于Oracle,直接使用原生连接
                if (config.Type.ToLower() == "oracle")
                {
                    using var connection = new OracleConnection(config.ConnectionString);
                    await connection.OpenAsync();
                    using var command = connection.CreateCommand();
                    command.CommandText = "SELECT SYSDATE FROM DUAL";
                    var result = await command.ExecuteScalarAsync();
                    if (result != null)
                    {
                        await connection.CloseAsync();
                        return (true, $"Oracle连接成功!当前时间: {result}");
                    }
                    else
                    {
                        return (false, "Oracle连接测试查询返回空结果");
                    }
                }
                else
                {
                    // 其他数据库使用SqlSugar
                    var tempManager = new DatabaseManager(config, "TestConnection", "127.0.0.1");
                    try
                    {
                        return await tempManager.TestConnectionAsync();
                    }
                    finally
                    {
                        tempManager.Dispose();
                    }
                }
            }
            catch (Exception ex)
            {
                return (false, $"连接失败: {ex.Message}");
            }
        }
        #endregion
        #region 辅助方法
        /// <summary>