S8LegacySqlDataProvider.cs 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. using Admin.NET.Plugin.AiDOP.Entity.S8;
  2. using SqlSugar;
  3. namespace Admin.NET.Plugin.AiDOP.Service.S8.Rules.DataAccess;
  4. /// <summary>
  5. /// LEGACY_SQL 取数抽象。抽出接口是为了让"STANDARD_DATASET 绝不回落 Legacy"
  6. /// 这条边界可以被测试真实验证(注入探针后断言调用次数为 0),而不是只靠代码审阅。
  7. /// </summary>
  8. public interface IS8LegacySqlDataProvider
  9. {
  10. Task<S8MonitoringDataResult> LoadAsync(
  11. long tenantId,
  12. long factoryId,
  13. AdoS8WatchRule rule,
  14. string ruleType,
  15. int timeoutSeconds,
  16. CancellationToken cancellationToken = default);
  17. }
  18. /// <summary>
  19. /// LEGACY_SQL 取数适配器:把既有"规则自带 expression + data_source_id"的取数结果
  20. /// 转换为统一的 canonical 行集合,使 evaluator 不再直接依赖 <see cref="System.Data.DataTable"/>。
  21. ///
  22. /// 本类**逐行保留迁移前的行为**(数据源查询条件、失败 reason 码、异常消息措辞),
  23. /// 132 条历史规则的运行结果因此不发生变化。
  24. /// </summary>
  25. public class S8LegacySqlDataProvider : IS8LegacySqlDataProvider, ITransient
  26. {
  27. private readonly SqlSugarRepository<AdoS8DataSource> _dataSourceRep;
  28. private readonly S8DataSourceRowLoader _rowLoader;
  29. public S8LegacySqlDataProvider(
  30. SqlSugarRepository<AdoS8DataSource> dataSourceRep,
  31. S8DataSourceRowLoader rowLoader)
  32. {
  33. _dataSourceRep = dataSourceRep;
  34. _rowLoader = rowLoader;
  35. }
  36. /// <summary>
  37. /// 按规则的 data_source_id + expression 取数。
  38. /// 数据源不可用 → data_source_unavailable;SQL/API 执行失败 → query_failed。两者 reason 码与迁移前一致。
  39. /// </summary>
  40. public async Task<S8MonitoringDataResult> LoadAsync(
  41. long tenantId,
  42. long factoryId,
  43. AdoS8WatchRule rule,
  44. string ruleType,
  45. int timeoutSeconds,
  46. CancellationToken cancellationToken = default)
  47. {
  48. var dataSource = await _dataSourceRep.AsQueryable()
  49. .Where(x => x.Id == rule.DataSourceId
  50. && x.TenantId == tenantId
  51. && x.FactoryId == factoryId
  52. && x.Enabled)
  53. .FirstAsync();
  54. if (dataSource == null
  55. || string.IsNullOrWhiteSpace(dataSource.Endpoint)
  56. || !S8DataSourceRowLoader.IsSupportedType(dataSource.Type))
  57. {
  58. throw new S8RuleEvaluatorException(
  59. "data_source_unavailable",
  60. $"{ruleType} 规则 {rule.RuleCode} 数据源不可用(id={rule.DataSourceId})");
  61. }
  62. System.Data.DataTable table;
  63. try
  64. {
  65. table = await _rowLoader.LoadAsync(
  66. dataSource,
  67. rule.Expression!,
  68. _dataSourceRep.Context.CurrentConnectionConfig.DbType,
  69. timeoutSeconds,
  70. cancellationToken);
  71. }
  72. catch (Exception ex)
  73. {
  74. throw new S8RuleEvaluatorException(
  75. "query_failed",
  76. $"{ruleType} 规则 {rule.RuleCode} 取数失败:{ex.Message}",
  77. ex);
  78. }
  79. return new S8MonitoringDataResult
  80. {
  81. RowSet = S8MonitoringRowSet.FromDataTable(table),
  82. DataSourceId = dataSource.Id,
  83. DataAccessMode = S8DataAccessMode.LegacySql
  84. };
  85. }
  86. }