Files
lserp_cs_6.0/插件库/Lskj.CommandKernel/DynamicModuleNativeExecution.cs
2026-08-14 14:28:28 +08:00

278 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
namespace Lskj.CommandKernel
{
/// <summary>
/// 当前数据库低代码配置解析出的服务端私有原生执行合同。它只描述
/// 已存在 ERP 保存族和事务/钩子语义,不携带表名、字段名或 SQL。
/// </summary>
public sealed class DynamicModuleNativeExecutionProfile
{
public string SchemaVersion { get; set; }
public string Action { get; set; }
public string ModuleCode { get; set; }
public string ModuleKind { get; set; }
public string NativeSaveFamily { get; set; }
public int ConfiguredSaveVersion { get; set; }
public bool DetailRowsRequired { get; set; }
public bool NativeConfirmationRetryRequired { get; set; }
public string TransactionPolicy { get; set; }
public string PostCommitPolicy { get; set; }
public string ConfigurationFingerprint { get; set; }
public string Fingerprint { get; set; }
}
/// <summary>
/// 把 ModuleInspection 中的 NewVer 和模块类型固定为原生执行族。
/// 配置、动作或执行族任一变化都会生成不同指纹;调用方必须在计划
/// 和确认后执行阶段各重新解析一次。
/// </summary>
public static class DynamicModuleNativeExecutionProfileResolver
{
private const string SchemaVersion = "1.0";
private const string TransactionPolicy =
"caller_owned_serializable";
private const string PostCommitPolicy =
"durable_outbox_then_native_hook";
public static DynamicModuleNativeExecutionProfile ResolveForCreate(
ModuleInspection inspection,
string configurationFingerprint)
{
ModuleInspector.EnsureCreateConfigured(inspection);
return Resolve(
inspection,
configurationFingerprint,
"create");
}
public static DynamicModuleNativeExecutionProfile ResolveForUpdate(
ModuleInspection inspection,
string configurationFingerprint)
{
ModuleInspector.EnsureUpdateConfigured(inspection);
if (!string.Equals(
inspection == null ? null : inspection.Kind,
"base",
StringComparison.OrdinalIgnoreCase))
{
throw Error(
"dynamic_module_update_bill_unsupported",
"通用单据修改尚未建立原生明细行身份与删除语义合同。");
}
return Resolve(
inspection,
configurationFingerprint,
"update");
}
public static void EnsureBound(
DynamicModuleNativeExecutionProfile profile,
string action,
string moduleCode,
string moduleKind,
string configurationFingerprint)
{
if (profile == null
|| profile.SchemaVersion != SchemaVersion
|| !string.Equals(
profile.Action,
action,
StringComparison.Ordinal)
|| !string.Equals(
profile.ModuleCode,
moduleCode,
StringComparison.Ordinal)
|| !string.Equals(
profile.ModuleKind,
moduleKind,
StringComparison.OrdinalIgnoreCase)
|| !string.Equals(
profile.ConfigurationFingerprint,
configurationFingerprint,
StringComparison.Ordinal)
|| profile.ConfiguredSaveVersion < 0
|| profile.ConfiguredSaveVersion > 100000
|| profile.TransactionPolicy != TransactionPolicy
|| profile.PostCommitPolicy != PostCommitPolicy
|| !ExpectedFamily(
profile.ModuleKind,
profile.ConfiguredSaveVersion).Equals(
profile.NativeSaveFamily,
StringComparison.Ordinal)
|| profile.DetailRowsRequired != string.Equals(
profile.ModuleKind,
"bill",
StringComparison.OrdinalIgnoreCase)
|| !profile.NativeConfirmationRetryRequired
|| !CommandInputFingerprint.IsValid(profile.Fingerprint)
|| !string.Equals(
profile.Fingerprint,
CreateFingerprint(profile),
StringComparison.Ordinal))
{
throw Error(
"dynamic_module_native_execution_profile_invalid",
"动态模块原生执行合同无效或未绑定当前模块、动作和配置。");
}
}
public static DynamicModuleNativeExecutionProfile Clone(
DynamicModuleNativeExecutionProfile profile)
{
if (profile == null) return null;
EnsureBound(
profile,
profile.Action,
profile.ModuleCode,
profile.ModuleKind,
profile.ConfigurationFingerprint);
return new DynamicModuleNativeExecutionProfile
{
SchemaVersion = profile.SchemaVersion,
Action = profile.Action,
ModuleCode = profile.ModuleCode,
ModuleKind = profile.ModuleKind,
NativeSaveFamily = profile.NativeSaveFamily,
ConfiguredSaveVersion = profile.ConfiguredSaveVersion,
DetailRowsRequired = profile.DetailRowsRequired,
NativeConfirmationRetryRequired =
profile.NativeConfirmationRetryRequired,
TransactionPolicy = profile.TransactionPolicy,
PostCommitPolicy = profile.PostCommitPolicy,
ConfigurationFingerprint =
profile.ConfigurationFingerprint,
Fingerprint = profile.Fingerprint
};
}
private static DynamicModuleNativeExecutionProfile Resolve(
ModuleInspection inspection,
string configurationFingerprint,
string action)
{
if (inspection == null || inspection.Configuration == null)
throw Error(
"module_parameter_contract_incomplete",
"模块低代码配置为空,不能解析原生保存合同。");
string moduleKind = (inspection.Kind ?? string.Empty)
.ToLowerInvariant();
if (moduleKind != "base" && moduleKind != "bill")
throw Error(
"module_kind_invalid",
"模块类型不是受支持的基础档案或单据。");
string currentConfiguration =
ModuleInspector.PrivateConfigurationFingerprint(inspection);
if (!CommandInputFingerprint.IsValid(configurationFingerprint)
|| !string.Equals(
configurationFingerprint,
currentConfiguration,
StringComparison.Ordinal))
{
throw Error(
"module_native_execution_configuration_changed",
"原生执行合同与当前低代码配置不一致,请重新读取模块参数。");
}
string rawVersion = ModuleInspector.Value(
inspection.Configuration,
"NewVer").Trim();
int configuredVersion = 0;
if (rawVersion.Length != 0
&& (!int.TryParse(
rawVersion,
NumberStyles.Integer,
CultureInfo.InvariantCulture,
out configuredVersion)
|| configuredVersion < 0
|| configuredVersion > 100000))
{
throw Error(
"dynamic_module_native_save_version_invalid",
"低代码 NewVer 不是受支持的非负整数,不能选择原生保存过程。");
}
DynamicModuleNativeExecutionProfile profile =
new DynamicModuleNativeExecutionProfile
{
SchemaVersion = SchemaVersion,
Action = action,
ModuleCode = inspection.ModuleCode,
ModuleKind = moduleKind,
NativeSaveFamily = ExpectedFamily(
moduleKind,
configuredVersion),
ConfiguredSaveVersion = configuredVersion,
DetailRowsRequired = moduleKind == "bill",
NativeConfirmationRetryRequired = true,
TransactionPolicy = TransactionPolicy,
PostCommitPolicy = PostCommitPolicy,
ConfigurationFingerprint = configurationFingerprint
};
profile.Fingerprint = CreateFingerprint(profile);
EnsureBound(
profile,
action,
inspection.ModuleCode,
moduleKind,
configurationFingerprint);
return profile;
}
private static string ExpectedFamily(
string moduleKind,
int configuredVersion)
{
bool legacy = configuredVersion == 0;
if (string.Equals(
moduleKind,
"base",
StringComparison.OrdinalIgnoreCase))
return legacy
? "legacy.base-save.p-base-save"
: "legacy.base-save.p-base-save70";
if (string.Equals(
moduleKind,
"bill",
StringComparison.OrdinalIgnoreCase))
return legacy
? "legacy.bill-save.p-bill-save-pr3"
: "legacy.bill-save.p-bill-save-pr70";
return string.Empty;
}
private static string CreateFingerprint(
DynamicModuleNativeExecutionProfile profile)
{
return CommandInputFingerprint.Create(
"dynamic-module.native-execution-profile",
new Dictionary<string, object>
{
{ "schemaVersion", profile.SchemaVersion },
{ "action", profile.Action },
{ "moduleCode", profile.ModuleCode },
{ "moduleKind", profile.ModuleKind },
{ "nativeSaveFamily", profile.NativeSaveFamily },
{ "configuredSaveVersion",
profile.ConfiguredSaveVersion },
{ "detailRowsRequired", profile.DetailRowsRequired },
{ "nativeConfirmationRetryRequired",
profile.NativeConfirmationRetryRequired },
{ "transactionPolicy", profile.TransactionPolicy },
{ "postCommitPolicy", profile.PostCommitPolicy },
{ "configurationFingerprint",
profile.ConfigurationFingerprint }
});
}
private static CommandKernelException Error(
string code,
string message)
{
return new CommandKernelException(code, message, 6);
}
}
}