278 lines
11 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|