| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 |
- namespace Admin.NET.Plugin.AiDOP.DataPlatform.Executors;
- /// <summary>
- /// 入站抽数(PULL)的工厂作用域语义 —— 与 <see cref="MdpStagingWriter.NormalizeFactoryId"/> 严格同源。
- ///
- /// 背景:部分源表(b_examine_result / b_bom_child_examine / srm_pr_main / ic_demandschedule 等)
- /// 把 factory_id 写成了 tenant_id(见 Order/ResourceCheckResultWriter:entry.FactoryId ?? order.FactoryId ?? entry.TenantId),
- /// 这类值并不是真实工厂,只是"没有工厂"的另一种写法。写入层 <see cref="MdpStagingWriter"/> 早已按
- /// NormalizeFactoryId 把 factory_id==tenant_id / 0 / NULL 统一归一成"无工厂"→回落到默认工厂 1;
- /// 若拉取层不做同样的归一,就会出现"拉取层判定不匹配→0 行,写入层却认为匹配"的口径分裂,
- /// 表现为长期 rows_read=0 但 status=SUCCESS 的静默空跑。
- ///
- /// 因此本类不新造口径,只把写入层已有的归一规则翻译成等价 SQL,保证两层永远一致。
- ///
- /// 与 <see cref="Admin.NET.Plugin.AiDOP.Infrastructure.SmartOpsOperationalFactory"/> 的区别(勿混用):
- /// 后者服务于 DWD/KPI **读取**侧,对 factory_id==tenant_id 的行采取"排除"策略
- /// (谓词里带 <c>col <> @tenantId</c>),因为那是脏数据不应计入运营事实;
- /// 而入站 PULL 侧必须"归一"而非"排除",否则整张源表会被丢光。两者语义方向相反,不可互相替换。
- /// </summary>
- internal static class MdpFactoryScope
- {
- /// <summary>历史/无工厂数据统一回落到的默认工厂号(与 MdpStagingWriter 的 resolvedFactory 回落一致)。</summary>
- internal const long LegacyDefaultFactoryId = 1;
- /// <summary>
- /// 把源行的 factory_id 归一成可比较的工厂号:
- /// NULL / <=0 / 等于 tenant_id 一律视为"无真实工厂",回落 <see cref="LegacyDefaultFactoryId"/>。
- /// </summary>
- internal static long Resolve(long tenantId, long? rowFactoryId)
- => MdpStagingWriter.NormalizeFactoryId(tenantId, rowFactoryId) ?? LegacyDefaultFactoryId;
- /// <summary>源行是否落在 (tenantId, scopeFactoryId) 作用域内(工厂维度)。</summary>
- internal static bool Matches(long tenantId, long scopeFactoryId, long? rowFactoryId)
- => Resolve(tenantId, rowFactoryId) == scopeFactoryId;
- /// <summary>
- /// <see cref="Resolve"/> 的等价 SQL(MySQL / SQL Server 通用)。
- /// <paramref name="quotedColumn"/> 需已按目标方言转义。
- /// <c>CASE WHEN col > 0 THEN col END</c> 而非 <c>NULLIF(col,0)</c> 是刻意的:
- /// NormalizeFactoryId 对负数同样返回 null,用 CASE 才能与之逐值等价。
- /// </summary>
- internal static string ResolveSqlExpression(string quotedColumn, string tenantParam)
- => $"COALESCE(NULLIF(CASE WHEN {quotedColumn} > 0 THEN {quotedColumn} END, {tenantParam}), {LegacyDefaultFactoryId})";
- /// <summary>工厂作用域谓词。注意:引用了 <paramref name="tenantParam"/>,调用方必须保证该参数已绑定。</summary>
- internal static string SqlPredicate(string quotedColumn, string tenantParam, string factoryParam)
- => $"{ResolveSqlExpression(quotedColumn, tenantParam)} = {factoryParam}";
- }
|