| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- using System.Data;
- using System.Globalization;
- namespace Admin.NET.Plugin.AiDOP.Service.S8.Rules.DataAccess;
- /// <summary>
- /// S8 监控数据的 canonical 单行。
- ///
- /// 设计约束(与迁移前 DataRow 读取语义严格一致,不得"顺手改进"):
- /// · 取值器缺列返回 null,不抛异常 —— evaluator 依赖此行为做 canonical→params 回退;
- /// · DBNull 与 null 等价,均返回 null;**绝不用字符串 "null" 表示空值**;
- /// · GetString 去首尾空白;GetDecimal / GetDateTime / GetLong 支持字符串与强类型两种来源
- /// (Legacy SQL 走 DataTable 常给字符串,标准 Provider 常给强类型);
- /// · <see cref="Values"/> 保留结果集全部原始列,payload 落盘依赖它。
- ///
- /// 列名比较一律 OrdinalIgnoreCase,与既有 payload 字典(StringComparer.OrdinalIgnoreCase)保持一致。
- /// </summary>
- public sealed class S8MonitoringRow
- {
- private readonly Dictionary<string, object?> _values;
- private S8MonitoringRow(Dictionary<string, object?> values) => _values = values;
- /// <summary>结果集原始列 → 值。缺失值为 null(不是 DBNull,不是 "null" 字符串)。</summary>
- public IReadOnlyDictionary<string, object?> Values => _values;
- /// <summary>由列值字典构造一行。标准 Provider 使用此入口。</summary>
- public static S8MonitoringRow FromValues(IReadOnlyDictionary<string, object?> values)
- {
- var copy = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
- foreach (var kv in values)
- copy[kv.Key] = kv.Value == DBNull.Value ? null : kv.Value;
- return new S8MonitoringRow(copy);
- }
- internal static S8MonitoringRow FromDataRow(DataRow row)
- {
- var values = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
- foreach (DataColumn column in row.Table.Columns)
- {
- var v = row[column];
- values[column.ColumnName] = v == DBNull.Value ? null : v;
- }
- return new S8MonitoringRow(values);
- }
- /// <summary>列是否存在于本行。</summary>
- public bool HasColumn(string? columnName) =>
- !string.IsNullOrWhiteSpace(columnName) && _values.ContainsKey(columnName!);
- private bool TryGetRaw(string? columnName, out object? value)
- {
- value = null;
- if (string.IsNullOrWhiteSpace(columnName)) return false;
- if (!_values.TryGetValue(columnName!, out var v)) return false;
- if (v is null) return false;
- value = v;
- return true;
- }
- /// <summary>读字符串并去首尾空白;缺列 / 空值返回 null。</summary>
- public string? GetString(string? columnName) =>
- TryGetRaw(columnName, out var v) ? Convert.ToString(v)?.Trim() : null;
- /// <summary>读时间;支持 DateTime 与可解析字符串。缺列 / 空值 / 无法解析返回 null。</summary>
- public DateTime? GetDateTime(string? columnName)
- {
- if (!TryGetRaw(columnName, out var v)) return null;
- if (v is DateTime dt) return dt;
- return DateTime.TryParse(Convert.ToString(v, CultureInfo.InvariantCulture), out var parsed) ? parsed : null;
- }
- /// <summary>读小数;支持数值与可解析字符串。缺列 / 空值 / 无法解析返回 null。</summary>
- public decimal? GetDecimal(string? columnName)
- {
- if (!TryGetRaw(columnName, out var v)) return null;
- if (v is decimal d) return d;
- return decimal.TryParse(
- Convert.ToString(v, CultureInfo.InvariantCulture),
- NumberStyles.Any,
- CultureInfo.InvariantCulture,
- out var parsed)
- ? parsed
- : null;
- }
- /// <summary>读长整型。缺列 / 空值 / 无法解析返回 null。</summary>
- public long? GetLong(string? columnName)
- {
- if (!TryGetRaw(columnName, out var v)) return null;
- if (v is long l) return l;
- return long.TryParse(Convert.ToString(v, CultureInfo.InvariantCulture), out var parsed) ? parsed : null;
- }
- }
|