DatabaseService.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. using Serilog;
  2. using SqlSugar;
  3. using YZWater.Core.Models;
  4. namespace YZWater.Core.Services;
  5. /// <summary>
  6. /// 数据库服务 - 使用 SqlSugar + SQLite
  7. /// </summary>
  8. public static class DatabaseService
  9. {
  10. private static SqlSugarClient? _db;
  11. private static readonly string DbPath = "yzwater.db";
  12. /// <summary>
  13. /// 数据库实例
  14. /// </summary>
  15. public static ISqlSugarClient Db => _db ?? throw new InvalidOperationException("数据库未初始化,请先调用 Initialize()");
  16. /// <summary>
  17. /// 初始化数据库(需先调用 LogService.Initialize())
  18. /// </summary>
  19. public static void Initialize()
  20. {
  21. InitDatabase();
  22. }
  23. private static void InitDatabase()
  24. {
  25. _db = new SqlSugarClient(new ConnectionConfig
  26. {
  27. ConnectionString = $"Data Source={DbPath}",
  28. DbType = DbType.Sqlite,
  29. IsAutoCloseConnection = true,
  30. InitKeyType = InitKeyType.Attribute
  31. });
  32. _db.Aop.OnLogExecuting = (sql, pars) =>
  33. {
  34. Log.Debug("SQL: {Sql}", sql);
  35. };
  36. _db.DbMaintenance.CreateDatabase();
  37. // 启用 SQLite WAL 模式(提升并发读写性能)
  38. try
  39. {
  40. _db.Ado.ExecuteCommand("PRAGMA journal_mode=WAL");
  41. _db.Ado.ExecuteCommand("PRAGMA synchronous=NORMAL"); // WAL 模式下推荐
  42. _db.Ado.ExecuteCommand("PRAGMA cache_size=-64000"); // 64MB 缓存
  43. _db.Ado.ExecuteCommand("PRAGMA temp_store=MEMORY"); // 临时表使用内存
  44. Log.Information("SQLite WAL 模式已启用");
  45. }
  46. catch (Exception ex)
  47. {
  48. Log.Warning(ex, "启用 WAL 模式失败(继续使用默认模式)");
  49. }
  50. // 逐个初始化表,单个失败不删除数据也不影响其他表
  51. var tables = new[] { typeof(Person), typeof(AlarmRecord), typeof(FlowRecord),
  52. typeof(EquipmentStatus), typeof(AuditLog), typeof(User),
  53. typeof(AnalogRecord) };
  54. foreach (var tableType in tables)
  55. {
  56. try
  57. {
  58. _db.CodeFirst.InitTables(tableType);
  59. }
  60. catch (Exception ex)
  61. {
  62. // 仅记录错误,继续初始化其他表,不删除数据库
  63. Log.Error(ex, "初始化表 {Table} 失败(保留已有数据,跳过此表)", tableType.Name);
  64. }
  65. }
  66. try
  67. {
  68. AuthService.Initialize();
  69. }
  70. catch (Exception ex)
  71. {
  72. Log.Error(ex, "AuthService 初始化失败(默认管理员可能未创建)");
  73. }
  74. // 创建索引以提升查询性能(忽略已存在的索引)
  75. try
  76. {
  77. CreateIndexes();
  78. }
  79. catch (Exception ex)
  80. {
  81. Log.Warning(ex, "创建索引失败(不影响功能)");
  82. }
  83. Log.Information("数据库初始化完成");
  84. }
  85. /// <summary>
  86. /// 创建常用查询索引
  87. /// </summary>
  88. private static void CreateIndexes()
  89. {
  90. var indexSqls = new[]
  91. {
  92. "CREATE INDEX IF NOT EXISTS idx_flow_record_time ON flow_records(RecordTime)",
  93. "CREATE INDEX IF NOT EXISTS idx_alarm_time ON alarm_records(AlarmTime)",
  94. "CREATE INDEX IF NOT EXISTS idx_equip_device_id ON equipment_status(DeviceId)",
  95. "CREATE INDEX IF NOT EXISTS idx_equip_update_time ON equipment_status(LastUpdateTime)",
  96. "CREATE INDEX IF NOT EXISTS idx_analog_record_time ON analog_records(RecordTime)",
  97. "CREATE INDEX IF NOT EXISTS idx_analog_tag_name ON analog_records(TagName)"
  98. };
  99. foreach (var sql in indexSqls)
  100. {
  101. try
  102. {
  103. _db!.Ado.ExecuteCommand(sql);
  104. }
  105. catch (Exception ex)
  106. {
  107. Log.Debug(ex, "创建索引失败: {Sql}", sql);
  108. }
  109. }
  110. }
  111. public static void Dispose()
  112. {
  113. _db?.Dispose();
  114. }
  115. }