diff --git a/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs b/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs index 1d4ef0f0..21949423 100644 --- a/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs +++ b/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs @@ -393,6 +393,35 @@ namespace YLErp.Modules.RiskEngine _logger.Info($"[风控引擎] 匹配 TriggerPoint 的应用数: {matchedApplications.Count}"); + // 汇总本次实际命中应用关联的结构化规则,变量定义只在本次检查开始时批量查询一次。 + // 同一规则可能被多个应用引用,先对规则 ID 去重,避免重复处理规则定义。 + var matchedRuleIds = matchedApplications + .SelectMany(application => ParseRuleIds(application.RuleIds)) + .Distinct(); + // 只保留当前规则缓存中存在的规则,配置中无效或已删除的规则 ID 仍由后续原有流程记录日志并跳过。 + var matchedRules = matchedRuleIds + .Where(ruleMap.ContainsKey) + .Select(ruleId => ruleMap[ruleId]); + // 自由文本规则不依赖变量定义;条件缓存为空的结构化规则继续在执行阶段按原逻辑报错。 + var structuredRules = matchedRules + .Where(rule => rule.Status == RiskRuleStatus.Active) + .Where(rule => !string.IsNullOrWhiteSpace(rule.ConditionJson)) + .Where(rule => rule.ParsedConditions != null && rule.ParsedConditions.Count > 0); + // 条件中的主变量和变量阈值都需要加载,多条规则引用同一变量时只保留一个 ID。 + var requiredVariableIds = structuredRules + .SelectMany(rule => RuleConditionExpressionBuilder.GetReferencedVariableIds(rule.ParsedConditions)) + .Distinct() + .ToList(); + + if (requiredVariableIds.Any()) + { + // 仅加载本次检查需要的变量,避免按规则逐次查询,也避免读取整个变量池。 + variables = ruleDbContext.glms_risk_variable + .AsNoTracking() + .Where(variable => requiredVariableIds.Contains(variable.id)) + .ToDictionary(variable => (long)variable.id); + } + // ============================================================ // Step 3: 遍历匹配的应用,通过 RuleIds 关联规则并执行预编译委托 // ============================================================ @@ -444,19 +473,6 @@ namespace YLErp.Modules.RiskEngine throw new InvalidOperationException("结构化规则条件缓存为空"); var referencedVariableIds = RuleConditionExpressionBuilder.GetReferencedVariableIds(conditions); - var missingVariableIds = referencedVariableIds - .Where(id => !variables.ContainsKey(id)) - .ToList(); - if (missingVariableIds.Any()) - { - // 按本次结构化规则实际引用的变量懒加载,避免每次风控检查全量读取变量池。 - var loadedVariables = ruleDbContext.glms_risk_variable - .AsNoTracking() - .Where(v => missingVariableIds.Contains(v.id)) - .ToDictionary(v => v.id); - foreach (var variable in loadedVariables) - variables[variable.Key] = variable.Value; - } var ruleVariables = referencedVariableIds .Where(variables.ContainsKey)