using Microsoft.Data.Sqlite; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows.Forms; namespace 報到系統客戶端.Data { /// /// SQLite 資料庫服務初始化和連線管理 /// public class DatabaseService { private static DatabaseService _instance; private static readonly object _lockObject = new object(); private string _databasePath; private SqliteConnection _connection; private const string DB_FILENAME = "data.db"; // 靜態資料表定義 private static readonly Dictionary> TableDefinitions = new Dictionary> { { "Classes", new List { new TableColumnDefinition { Name = "ID", Type = "INTEGER PRIMARY KEY", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CourseCode", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CourseName", Type = "TEXT", IsNotNull = true, DefaultValue = null }, new TableColumnDefinition { Name = "CourseDate", Type = "DATETIME", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CourseLocation", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "NotificationTemplate", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "AgreedTerms", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "StartTime", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "EndTime", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CreatedAt", Type = "DATETIME", IsNotNull = false, DefaultValue = "CURRENT_TIMESTAMP" }, new TableColumnDefinition { Name = "UpdatedAt", Type = "DATETIME", IsNotNull = false, DefaultValue = "CURRENT_TIMESTAMP" } } }, { "SignUps", new List { new TableColumnDefinition { Name = "ID", Type = "INTEGER PRIMARY KEY AUTOINCREMENT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CourseID", Type = "INTEGER", IsNotNull = true, DefaultValue = null }, new TableColumnDefinition { Name = "SeqNo", Type = "INTEGER", IsNotNull = true, DefaultValue = "0" }, new TableColumnDefinition { Name = "Name", Type = "TEXT", IsNotNull = true, DefaultValue = null }, new TableColumnDefinition { Name = "Mobile", Type = "TEXT", IsNotNull = true, DefaultValue = null }, new TableColumnDefinition { Name = "QRCode", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "SignUpType", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "IDNumber", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "IDType", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "MealType", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "Email", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "LossJobTimes", Type = "INTEGER", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "Gender", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "AgreementStatus", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CheckInTime", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CheckOutTime", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CreatedAt", Type = "DATETIME", IsNotNull = false, DefaultValue = "CURRENT_TIMESTAMP" }, new TableColumnDefinition { Name = "UpdatedAt", Type = "DATETIME", IsNotNull = false, DefaultValue = "CURRENT_TIMESTAMP" } } }, { "BPSN", new List { new TableColumnDefinition { Name = "BPENO", Type = "TEXT PRIMARY KEY", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "BPNME", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "BPAWD", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "Is系統管理群組", Type = "BOOLEAN", IsNotNull = false, DefaultValue = "0" }, new TableColumnDefinition { Name = "Is客戶管理群組", Type = "BOOLEAN", IsNotNull = false, DefaultValue = "0" }, new TableColumnDefinition { Name = "Is現場工作群組", Type = "BOOLEAN", IsNotNull = false, DefaultValue = "0" }, new TableColumnDefinition { Name = "Is查詢群組", Type = "BOOLEAN", IsNotNull = false, DefaultValue = "0" }, new TableColumnDefinition { Name = "CreatedAt", Type = "DATETIME", IsNotNull = false, DefaultValue = "CURRENT_TIMESTAMP" }, new TableColumnDefinition { Name = "UpdatedAt", Type = "DATETIME", IsNotNull = false, DefaultValue = "CURRENT_TIMESTAMP" } } }, { "CheckIn", new List { new TableColumnDefinition { Name = "ID", Type = "INTEGER PRIMARY KEY AUTOINCREMENT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CourseID", Type = "INTEGER", IsNotNull = true, DefaultValue = null }, new TableColumnDefinition { Name = "Name", Type = "TEXT", IsNotNull = true, DefaultValue = null }, new TableColumnDefinition { Name = "Mobile", Type = "TEXT", IsNotNull = true, DefaultValue = null }, new TableColumnDefinition { Name = "SignUpType", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "IDNumber", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "IDType", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "MealType", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "Email", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "LossJobTimes", Type = "INTEGER", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "Gender", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "AgreementStatus", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CheckInType", Type = "TEXT", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CheckInTime", Type = "DATETIME", IsNotNull = true, DefaultValue = null }, new TableColumnDefinition { Name = "UploadTime", Type = "DATETIME", IsNotNull = false, DefaultValue = null }, new TableColumnDefinition { Name = "CreatedAt", Type = "DATETIME", IsNotNull = false, DefaultValue = "CURRENT_TIMESTAMP" }, new TableColumnDefinition { Name = "UpdatedAt", Type = "DATETIME", IsNotNull = false, DefaultValue = "CURRENT_TIMESTAMP" } } } }; private static readonly Dictionary TableIndexes = new Dictionary { { "Classes", new[] { "idx_classes_courseid|CourseCode" } }, { "SignUps", new[] { "idx_signups_courseid|CourseID", "idx_signups_seqno|SeqNo", "idx_signups_qrcode|QRCode", "idx_signups_name|Name", "idx_signups_mobile|Mobile", "idx_signups_idnumber|IDNumber", "idx_signups_email|Email" }}, { "BPSN", new[] { "idx_bpsn_bpeno|BPENO" } }, { "CheckIn", new[] { "idx_checkin_courseid|CourseID", "idx_checkin_name|Name", "idx_checkin_mobile|Mobile", "idx_checkin_idnumber|IDNumber", "idx_checkin_email|Email", "idx_checkin_checkintime|CheckInTime" }} }; /// /// 取得單一實例 /// public static DatabaseService Instance { get { if (_instance == null) { lock (_lockObject) { if (_instance == null) { _instance = new DatabaseService(); } } } return _instance; } } public string DatabasePath { get { return _databasePath; } } private DatabaseService() { try { // 設定資料庫路徑 AppData\Roaming\報到系統客戶端 string appDataPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "報到系統客戶端" ); // 如果資料夾不存在則建立 if (!Directory.Exists(appDataPath)) { Directory.CreateDirectory(appDataPath); } // 建立 DB 子資料夾 string dbPath = Path.Combine(appDataPath, "DB"); if (!Directory.Exists(dbPath)) { Directory.CreateDirectory(dbPath); } _databasePath = Path.Combine(dbPath, DB_FILENAME); // 初始化資料庫 InitializeDatabase(); } catch (Exception ex) { throw new Exception($"初始化資料庫服務失敗:{ex.Message}", ex); } } /// /// 取得資料庫連線 /// public SqliteConnection GetConnection() { try { if (_connection == null || _connection.State == System.Data.ConnectionState.Closed) { // 使用改進的連線字串,設定更多參數確保穩定性 string connectionString = string.Format( "Data Source={0};", _databasePath ); _connection = new SqliteConnection(connectionString); _connection.Open(); } return _connection; } catch (DllNotFoundException ex) { throw new Exception( "無法載入 SQLite 原生庫 (e_sqlite3.dll)。\n\n" + "請嘗試以下方案:\n" + "1. 確認專案目標平台設定(x86 或 x64)\n" + "2. 在 NuGet Package Manager 執行:\n" + " - Update-Package System.Data.SQLite -Reinstall\n" + "3. 確認應用程式執行的平台與編譯平台相符\n" + "4. 清理並重新編譯專案\n\n" + "原始錯誤:" + ex.Message, ex); } catch (Exception ex) { throw new Exception($"開啟資料庫連線失敗:{ex.Message}", ex); } } /// /// 初始化資料庫(建立表格) /// private void InitializeDatabase() { try { var conn = GetConnection(); // 根據定義動態建立所有表格 foreach (var tableName in TableDefinitions.Keys) { CreateTableFromDefinition(conn, tableName); CreateIndexesForTable(conn, tableName); } } catch (Exception ex) { throw new Exception($"初始化資料庫失敗:{ex.Message}", ex); } } /// /// 根據定義動態建立表格 /// private void CreateTableFromDefinition(SqliteConnection conn, string tableName) { try { if (!TableDefinitions.ContainsKey(tableName)) { throw new Exception($"找不到表格 {tableName} 的定義"); } string sql = BuildCreateTableSql(tableName); using (SqliteCommand cmd = new SqliteCommand(sql, conn)) { cmd.ExecuteNonQuery(); } } catch (Exception ex) { throw new Exception($"建立表格 {tableName} 失敗:{ex.Message}", ex); } } /// /// 根據定義建立表格索引 /// private void CreateIndexesForTable(SqliteConnection conn, string tableName) { try { if (!TableIndexes.ContainsKey(tableName)) { return; } var indexes = TableIndexes[tableName]; foreach (var indexDef in indexes) { string[] parts = indexDef.Split('|'); if (parts.Length == 2) { string indexName = parts[0]; string columnName = parts[1]; string sql = $"CREATE INDEX IF NOT EXISTS {indexName} ON {tableName}({columnName})"; using (SqliteCommand cmd = new SqliteCommand(sql, conn)) { cmd.ExecuteNonQuery(); } } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"建立表格 {tableName} 索引失敗:{ex.Message}"); } } /// /// 動態構建 CREATE TABLE SQL 語句 /// private string BuildCreateTableSql(string tableName) { if (!TableDefinitions.ContainsKey(tableName)) { throw new Exception($"找不到表格 {tableName} 的定義"); } var columns = TableDefinitions[tableName]; var columnSql = new List(); foreach (var column in columns) { string colDef = $"{column.Name} {column.Type}"; if (column.IsNotNull) { colDef += " NOT NULL"; } if (!string.IsNullOrEmpty(column.DefaultValue)) { colDef += $" DEFAULT {column.DefaultValue}"; } columnSql.Add(colDef); } string sql = $"CREATE TABLE IF NOT EXISTS {tableName} (\n " + string.Join(",\n ", columnSql) + "\n)"; return sql; } /// /// 動態構建 ALTER TABLE ADD COLUMN SQL 語句 /// private string BuildAddColumnSql(string tableName, TableColumnDefinition column) { string colDef = $"{column.Name} {column.Type}"; if (column.IsNotNull) { colDef += " NOT NULL"; } if (!string.IsNullOrEmpty(column.DefaultValue)) { colDef += $" DEFAULT {column.DefaultValue}"; } return $"ALTER TABLE {tableName} ADD COLUMN {colDef}"; } /// /// 清除所有表格資料 /// public void ClearAllTables() { try { var conn = GetConnection(); // 清除 SignUps 表 using (SqliteCommand cmd = new SqliteCommand("DELETE FROM SignUps", conn)) { cmd.ExecuteNonQuery(); } // 清除 Classes 表 using (SqliteCommand cmd = new SqliteCommand("DELETE FROM Classes", conn)) { cmd.ExecuteNonQuery(); } // 清除 BPSN 表 using (SqliteCommand cmd = new SqliteCommand("DELETE FROM BPSN", conn)) { cmd.ExecuteNonQuery(); } // 清除 CheckIn 表 using (SqliteCommand cmd = new SqliteCommand("DELETE FROM CheckIn", conn)) { cmd.ExecuteNonQuery(); } // 重設自動遞增序號 using (SqliteCommand cmd = new SqliteCommand("DELETE FROM sqlite_sequence", conn)) { cmd.ExecuteNonQuery(); } } catch (Exception ex) { throw new Exception($"清除表格失敗:{ex.Message}", ex); } } /// /// 檢查資料表是否存在 /// public bool TableExists(string tableName) { try { var conn = GetConnection(); string sql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=@tableName"; using (SqliteCommand cmd = new SqliteCommand(sql, conn)) { cmd.Parameters.AddWithValue("@tableName", tableName); Int64 count = (Int64)cmd.ExecuteScalar(); return count > 0; } } catch (Exception ex) { throw new Exception($"檢查表格是否存在失敗:{ex.Message}", ex); } } /// /// 重建所有資料表 /// public void DropAndCreateAllTables() { try { var conn = GetConnection(); // 刪除表格順序很重要,需要考慮外鍵關係 // 從靜態定義中取得表格名稱,並按反向順序刪除 var tableNames = new List(TableDefinitions.Keys); tableNames.Reverse(); foreach (string tableName in tableNames) { string sql = $"DROP TABLE IF EXISTS {tableName}"; using (SqliteCommand cmd = new SqliteCommand(sql, conn)) { cmd.ExecuteNonQuery(); } } // 重新初始化資料庫結構 InitializeDatabase(); } catch (Exception ex) { throw new Exception($"刪除表格失敗:{ex.Message}", ex); } } /// /// 刪除指定的資料表 /// public void DropTable(string tableName) { try { if (string.IsNullOrWhiteSpace(tableName)) { throw new ArgumentException("表格名稱不能為空", nameof(tableName)); } var conn = GetConnection(); string sql = $"DROP TABLE IF EXISTS {tableName}"; using (SqliteCommand cmd = new SqliteCommand(sql, conn)) { cmd.ExecuteNonQuery(); } } catch (Exception ex) { throw new Exception($"刪除表格失敗:{ex.Message}", ex); } } /// /// 取得表格中現有的欄位名稱列表 /// private HashSet GetExistingColumnNames(string tableName) { var columnNames = new HashSet(); try { var columns = GetTableColumns(tableName); foreach (var column in columns) { columnNames.Add(column.ColumnName); } } catch { // 忽略錯誤 } return columnNames; } /// /// 獲取資料表的列信息 /// public List GetTableColumns(string tableName) { var columns = new List(); try { var conn = GetConnection(); string sql = $"PRAGMA table_info({tableName})"; using (SqliteCommand cmd = new SqliteCommand(sql, conn)) { using (SqliteDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { columns.Add(new TableColumnInfo { ColumnId = reader.GetInt32(0), ColumnName = reader.GetString(1), ColumnType = reader.GetString(2), IsNotNull = reader.GetInt32(3) != 0, DefaultValue = reader.IsDBNull(4) ? null : reader.GetString(4), IsPrimaryKey = reader.GetInt32(5) != 0 }); } } } } catch (Exception ex) { throw new Exception($"獲取表格列信息失敗:{ex.Message}", ex); } return columns; } /// /// 檢查並補足缺少的欄位 /// public void AddMissingColumns() { try { var conn = GetConnection(); foreach (var tableName in TableDefinitions.Keys) { if (!TableExists(tableName)) { System.Diagnostics.Debug.WriteLine($"表格 {tableName} 不存在,跳過欄位檢查"); continue; } var expectedColumns = TableDefinitions[tableName]; var existingColumnNames = GetExistingColumnNames(tableName); foreach (var column in expectedColumns) { if (!existingColumnNames.Contains(column.Name)) { try { string sql = BuildAddColumnSql(tableName, column); using (SqliteCommand cmd = new SqliteCommand(sql, conn)) { cmd.ExecuteNonQuery(); } System.Diagnostics.Debug.WriteLine($"已新增欄位 {tableName}.{column.Name}"); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"新增欄位 {tableName}.{column.Name} 失敗:{ex.Message}"); } } } } } catch (Exception ex) { throw new Exception($"檢查並新增缺少的欄位失敗:{ex.Message}", ex); } } /// /// 驗證所有表格的結構是否符合定義 /// public bool ValidateAllTablesStructure() { try { foreach (var tableName in TableDefinitions.Keys) { if (!ValidateSingleTableStructure(tableName)) { return false; } } return true; } catch { return false; } } /// /// 驗證單一表格的結構是否符合定義 /// public bool ValidateSingleTableStructure(string tableName) { try { if (!TableDefinitions.ContainsKey(tableName)) { throw new Exception($"找不到表格 {tableName} 的定義"); } if (!TableExists(tableName)) { return false; } var expectedColumns = TableDefinitions[tableName]; var existingColumnNames = GetExistingColumnNames(tableName); foreach (var expectedColumn in expectedColumns) { if (!existingColumnNames.Contains(expectedColumn.Name)) { System.Diagnostics.Debug.WriteLine($"表格 {tableName} 缺少欄位:{expectedColumn.Name}"); return false; } } return true; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"驗證表格 {tableName} 結構失敗:{ex.Message}"); return false; } } /// /// 獲取所有表格與其定義的結構對比結果 /// public Dictionary ValidateAllTablesStructureDetailed() { var results = new Dictionary(); foreach (var tableName in TableDefinitions.Keys) { results[tableName] = ValidateSingleTableStructureDetailed(tableName); } return results; } /// /// 獲取單一表格與定義的結構對比結果(詳細版) /// public TableStructureValidationResult ValidateSingleTableStructureDetailed(string tableName) { var result = new TableStructureValidationResult { TableName = tableName }; try { if (!TableDefinitions.ContainsKey(tableName)) { result.IsValid = false; result.Message = $"找不到表格 {tableName} 的定義"; return result; } if (!TableExists(tableName)) { result.IsValid = false; result.Message = $"表格 {tableName} 不存在"; result.MissingColumns = new List(TableDefinitions[tableName].Count); foreach (var col in TableDefinitions[tableName]) { result.MissingColumns.Add(col.Name); } return result; } var expectedColumns = TableDefinitions[tableName]; var existingColumns = GetTableColumns(tableName); var existingColumnNames = GetExistingColumnNames(tableName); result.MissingColumns = new List(); result.ExtraColumns = new List(); // 檢查缺少的欄位 foreach (var expectedColumn in expectedColumns) { if (!existingColumnNames.Contains(expectedColumn.Name)) { result.MissingColumns.Add(expectedColumn.Name); } } // 檢查多餘的欄位 foreach (var existingColumn in existingColumns) { if (!expectedColumns.Any(c => c.Name == existingColumn.ColumnName)) { result.ExtraColumns.Add(existingColumn.ColumnName); } } result.IsValid = result.MissingColumns.Count == 0 && result.ExtraColumns.Count == 0; if (result.IsValid) { result.Message = $"表格 {tableName} 結構驗證成功"; } else { var issues = new List(); if (result.MissingColumns.Count > 0) { issues.Add($"缺少 {result.MissingColumns.Count} 個欄位:{string.Join(", ", result.MissingColumns)}"); } if (result.ExtraColumns.Count > 0) { issues.Add($"有 {result.ExtraColumns.Count} 個多餘欄位:{string.Join(", ", result.ExtraColumns)}"); } result.Message = string.Join(";", issues); } } catch (Exception ex) { result.IsValid = false; result.Message = $"驗證表格 {tableName} 結構失敗:{ex.Message}"; } return result; } /// /// 執行資料庫健康檢查 /// public DatabaseHealthCheckResult PerformHealthCheck() { var healthCheckResult = new DatabaseHealthCheckResult(); healthCheckResult.CheckTime = DateTime.Now; try { // 檢查所有表格是否存在 healthCheckResult.AllTablesExist = true; foreach (var tableName in TableDefinitions.Keys) { if (!TableExists(tableName)) { healthCheckResult.AllTablesExist = false; if (healthCheckResult.MissingTables == null) { healthCheckResult.MissingTables = new List(); } healthCheckResult.MissingTables.Add(tableName); } } // 驗證所有表格結構 var validationResults = ValidateAllTablesStructureDetailed(); healthCheckResult.TableValidationResults = validationResults; healthCheckResult.AllTablesValid = validationResults.Values.All(r => r.IsValid); // 獲取資料庫統計信息 healthCheckResult.TablesStatistics = GetAllTablesStatistics(); // 獲取資料庫檔案大小 healthCheckResult.DatabaseFileSize = GetDatabaseFileSize(); healthCheckResult.DatabaseFileSizeFormatted = GetDatabaseFileSizeFormatted(); healthCheckResult.IsHealthy = healthCheckResult.AllTablesExist && healthCheckResult.AllTablesValid; } catch (Exception ex) { healthCheckResult.IsHealthy = false; healthCheckResult.ErrorMessage = ex.Message; } return healthCheckResult; } /// /// 自動修復資料庫結構(根據定義補足缺少的欄位) /// public DatabaseRepairResult AutoRepairDatabase() { var repairResult = new DatabaseRepairResult(); repairResult.RepairTime = DateTime.Now; try { var conn = GetConnection(); foreach (var tableName in TableDefinitions.Keys) { var tableRepairResult = new TableRepairResult { TableName = tableName }; if (!TableExists(tableName)) { // 建立缺少的表格 try { CreateTableFromDefinition(conn, tableName); CreateIndexesForTable(conn, tableName); tableRepairResult.IsRepaired = true; tableRepairResult.Message = $"表格 {tableName} 已建立"; tableRepairResult.Action = "CreateTable"; } catch (Exception ex) { tableRepairResult.IsRepaired = false; tableRepairResult.Message = $"建立表格 {tableName} 失敗:{ex.Message}"; tableRepairResult.Action = "CreateTable"; } } else { // 補足缺少的欄位 var expectedColumns = TableDefinitions[tableName]; var existingColumnNames = GetExistingColumnNames(tableName); var addedColumns = new List(); foreach (var column in expectedColumns) { if (!existingColumnNames.Contains(column.Name)) { try { string sql = BuildAddColumnSql(tableName, column); using (SqliteCommand cmd = new SqliteCommand(sql, conn)) { cmd.ExecuteNonQuery(); } addedColumns.Add(column.Name); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"新增欄位 {tableName}.{column.Name} 失敗:{ex.Message}"); } } } if (addedColumns.Count > 0) { tableRepairResult.IsRepaired = true; tableRepairResult.Message = $"已新增 {addedColumns.Count} 個欄位:{string.Join(", ", addedColumns)}"; tableRepairResult.Action = "AddColumns"; tableRepairResult.AddedColumns = addedColumns; } else { tableRepairResult.IsRepaired = true; tableRepairResult.Message = $"表格 {tableName} 無需修復"; tableRepairResult.Action = "NoAction"; } } repairResult.TableRepairResults.Add(tableRepairResult); } repairResult.IsSuccessful = repairResult.TableRepairResults.All(r => r.IsRepaired); } catch (Exception ex) { repairResult.IsSuccessful = false; repairResult.ErrorMessage = ex.Message; } return repairResult; } /// /// 關閉資料庫連線 /// public void CloseConnection() { try { if (_connection != null && _connection.State != System.Data.ConnectionState.Closed) { _connection.Close(); _connection.Dispose(); _connection = null; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"關閉連線時發生錯誤:{ex.Message}"); } } /// /// 獲取所有資料表的統計信息 /// public List GetAllTablesStatistics() { var statistics = new List(); foreach (var tableName in TableDefinitions.Keys) { try { if (TableExists(tableName)) { var conn = GetConnection(); string sql = $"SELECT COUNT(*) FROM {tableName}"; using (SqliteCommand cmd = new SqliteCommand(sql, conn)) { int recordCount = (int)cmd.ExecuteScalar(); statistics.Add(new TableStatistics { TableName = tableName, RecordCount = recordCount, CheckTime = DateTime.Now }); } } } catch { // 跳過無法取得統計信息的表格 } } return statistics; } /// /// 獲取資料庫檔案大小(單位:字節) /// public long GetDatabaseFileSize() { try { if (File.Exists(_databasePath)) { var fileInfo = new FileInfo(_databasePath); return fileInfo.Length; } return 0; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"獲取資料庫文件大小失敗:{ex.Message}"); return 0; } } /// /// 獲取資料庫檔案大小的格式化字符串(KB、MB等) /// public string GetDatabaseFileSizeFormatted() { long sizeInBytes = GetDatabaseFileSize(); string[] sizes = { "B", "KB", "MB", "GB" }; double len = sizeInBytes; int order = 0; while (len >= 1024 && order < sizes.Length - 1) { order++; len = len / 1024; } return $"{len:0.##} {sizes[order]}"; } } /// /// 資料表欄位定義 /// public class TableColumnDefinition { public string Name { get; set; } public string Type { get; set; } public bool IsNotNull { get; set; } public string DefaultValue { get; set; } } /// /// 資料表列信息 /// public class TableColumnInfo { public int ColumnId { get; set; } public string ColumnName { get; set; } public string ColumnType { get; set; } public bool IsNotNull { get; set; } public string DefaultValue { get; set; } public bool IsPrimaryKey { get; set; } } /// /// 資料表統計信息 /// public class TableStatistics { public string TableName { get; set; } public int RecordCount { get; set; } public DateTime CheckTime { get; set; } } /// /// 表格結構驗證結果 /// public class TableStructureValidationResult { public string TableName { get; set; } public bool IsValid { get; set; } public string Message { get; set; } public List MissingColumns { get; set; } public List ExtraColumns { get; set; } } /// /// 資料庫健康檢查結果 /// public class DatabaseHealthCheckResult { public DateTime CheckTime { get; set; } public bool IsHealthy { get; set; } public bool AllTablesExist { get; set; } public bool AllTablesValid { get; set; } public List MissingTables { get; set; } public Dictionary TableValidationResults { get; set; } public List TablesStatistics { get; set; } public long DatabaseFileSize { get; set; } public string DatabaseFileSizeFormatted { get; set; } public string ErrorMessage { get; set; } } /// /// 表格修復結果 /// public class TableRepairResult { public string TableName { get; set; } public bool IsRepaired { get; set; } public string Message { get; set; } public string Action { get; set; } // "CreateTable", "AddColumns", "NoAction" public List AddedColumns { get; set; } } /// /// 資料庫修復結果 /// public class DatabaseRepairResult { public DateTime RepairTime { get; set; } public bool IsSuccessful { get; set; } public List TableRepairResults { get; set; } public string ErrorMessage { get; set; } public DatabaseRepairResult() { TableRepairResults = new List(); } } }