20260919211702
This commit is contained in:
1 parent
f56e70b050
commit
f4bfc1ddfc
97 files changed
+6059
-1712
No files matched your search
+12
-14
@@ -205,7 +205,7 @@ create table dbo.s_relation (
|
||||
b_target_module_id varchar(50) not null, -- 目标模块
|
||||
b_target_field varchar(50) not null, -- 目标字段
|
||||
b_relation_type varchar(20) not null, -- one_to_one / one_to_many / many_to_one
|
||||
b_on_delete varchar(20) not null default 'none', -- 删除连带:none不连带 / cascade连带删除 / archive连带归档
|
||||
b_on_delete varchar(20) not null default 'restrict', -- 删除处置:restrict有外部引用即拒绝 / cascade连带删除 / none不处理不保护
|
||||
b_canuse tinyint not null default 1, -- 是否启用(0/1)
|
||||
b_xh int not null default 0, -- 显示顺序
|
||||
primary key (
|
||||
@@ -226,21 +226,19 @@ create index ix_s_relation_target
|
||||
GO
|
||||
|
||||
/* ============================================================================
|
||||
9.1 删除规则
|
||||
9.1 删除 SQL 规则
|
||||
|
||||
挂在模块(业务条件:勾条件 / 写 SQL)或模块关系(存在引用即拒绝删除)上的删除前规则。
|
||||
规则类型不单独存列,由 b_predicate 推断:空=引用规则;JSON=勾条件;其余=SQL 文本。
|
||||
b_scope_id 是挂载对象的业务键:模块=模块编码;关系=源模块|源字段|目标模块|目标字段。
|
||||
主键用雪花 id(新增时前端取号,与业务表一致):规则没有天然业务键,也不要求 IT 填编码。
|
||||
模块级“什么情况下不允许删除”的规则:b_sql 是只读查询,返回至少一行即拒绝本批删除。
|
||||
只服务模块删除(target=module);无模块的技术表走直接删除,不受本表约束。
|
||||
关系上的关联处置(含引用保护)由 s_relation.b_on_delete 表达,不再挂规则行。
|
||||
主键用雪花 id(新增时前端取号):规则没有天然业务键,也不要求 IT 填编码。
|
||||
============================================================================ */
|
||||
|
||||
create table dbo.s_rule (
|
||||
create table dbo.s_delete_rule (
|
||||
b_id bigint not null, -- 雪花主键(新增时前端经 /data/nextid 取号)
|
||||
b_scope_type varchar(20) not null, -- module / relation(挂载范围)
|
||||
b_scope_id varchar(250) not null, -- module=模块编码;relation=源模块|源字段|目标模块|目标字段
|
||||
b_hook varchar(30) not null, -- delete.pre(一期只做这个),save.pre 留位
|
||||
b_predicate nvarchar(max) null, -- 空=引用规则;JSON={"kind":"dsl","expr":…}=勾条件;其余=SQL 文本
|
||||
b_message nvarchar(500) null, -- 提示文案(写 SQL 必填;勾条件可空,引擎按条件自动生成)
|
||||
b_module_id varchar(50) not null, -- 规则所属数据模块编码(对应 s_module.b_id)
|
||||
b_sql nvarchar(max) not null, -- 只读查询 SQL,用 :ids 标记本次待删 ID 集合
|
||||
b_message nvarchar(500) null, -- 删除失败时的提示文案(第一阶段固定文案)
|
||||
b_canuse tinyint not null default 1, -- 是否启用(0/1)
|
||||
b_xh int not null default 0, -- 执行顺序(并列按 b_xh、b_id)
|
||||
b_created_by varchar(50) null, -- 审计列由服务端维护,配置界面不提交
|
||||
@@ -251,8 +249,8 @@ create table dbo.s_rule (
|
||||
);
|
||||
GO
|
||||
|
||||
create index ix_s_rule_scope
|
||||
on dbo.s_rule (b_scope_type, b_scope_id, b_hook, b_canuse, b_xh);
|
||||
create index ix_s_delete_rule_module
|
||||
on dbo.s_delete_rule (b_module_id, b_canuse, b_xh);
|
||||
GO
|
||||
|
||||
/* ============================================================================
|
||||
|
||||
@@ -1,47 +1,100 @@
|
||||
/* ============================================================================
|
||||
删除规则一期:s_relation 加删除连带列 + 新建规则表 s_rule
|
||||
删除策略重构:s_relation 删除处置三值 + 新建删除 SQL 规则表 s_delete_rule
|
||||
----------------------------------------------------------------------------
|
||||
背景:见 FMS删除规则引擎设计.md(一期只落配置,后端引擎二期做)。
|
||||
依据:FMS删除策略重构设计.md v1.2
|
||||
第一阶段元数据脚本,只改结构,不含初始化数据。
|
||||
本脚本可重复执行:
|
||||
- s_relation.b_on_delete 不存在时才加(存量行回填 'none');
|
||||
- s_rule 直接重建(drop + create)——表里还没有规则数据时才可执行,
|
||||
库中已有配置数据时请勿运行,改为手工迁移。
|
||||
- s_relation.b_on_delete 不存在时才加,且默认值取 'restrict';
|
||||
- 存量关系的 b_on_delete 不批量回填(设计 §3.1:避免上线后突然改变存量删除行为);
|
||||
仅把历史遗留的 'archive' 归一到 'none'(阶段一不支持归档,避免执行器遇到未知值);
|
||||
- s_delete_rule 不存在才建;旧的 s_rule 已废弃,按需手工 drop(见文件末尾说明)。
|
||||
执行:fms-api 目录下
|
||||
java -cp "tools/migration/mssql-jdbc-13.4.0.jre11.jar" tools/migration/RunSqlFile.java \
|
||||
../sql/fms_delete_rule.sql --dry-run
|
||||
确认分批正确后去掉 --dry-run 实跑(按 GO 分批、单事务、失败整体回滚)。
|
||||
============================================================================ */
|
||||
|
||||
/* 1. b_on_delete:补列并设定新语义的默认值。
|
||||
新值域 restrict / cascade / none;默认 restrict 只作用于新建行,
|
||||
存量行保持原值(历史为 'none'),由单独迁移决定是否升级。 */
|
||||
if col_length('dbo.s_relation', 'b_on_delete') is null
|
||||
begin
|
||||
alter table dbo.s_relation add
|
||||
b_on_delete varchar(20) not null default 'none'; -- none不连带 / cascade连带删除 / archive连带归档
|
||||
b_on_delete varchar(20) not null
|
||||
constraint df_s_relation_on_delete default 'restrict';
|
||||
end
|
||||
GO
|
||||
|
||||
drop table if exists dbo.s_rule;
|
||||
/* 2. 列已存在时,只改默认值约束,不动存量数据。 */
|
||||
if col_length('dbo.s_relation', 'b_on_delete') is not null
|
||||
begin
|
||||
declare @constraint sysname;
|
||||
select @constraint = dc.name
|
||||
from sys.default_constraints dc
|
||||
join sys.columns c
|
||||
on c.object_id = dc.parent_object_id
|
||||
and c.column_id = dc.parent_column_id
|
||||
where dc.parent_object_id = object_id('dbo.s_relation')
|
||||
and c.name = 'b_on_delete';
|
||||
|
||||
if @constraint is not null
|
||||
begin
|
||||
declare @dropSql nvarchar(400) =
|
||||
N'alter table dbo.s_relation drop constraint ' + quotename(@constraint);
|
||||
exec sp_executesql @dropSql;
|
||||
end
|
||||
|
||||
alter table dbo.s_relation add
|
||||
constraint df_s_relation_on_delete default 'restrict' for b_on_delete;
|
||||
end
|
||||
GO
|
||||
|
||||
/* 删除规则表:挂在模块(业务条件)或模块关系(存在引用即拒绝删除)上。
|
||||
规则类型不单独存列,由 b_predicate 推断:空=引用规则;JSON=勾条件;其余=SQL 文本。
|
||||
主键用雪花 id(新增时前端取号,与业务表一致):规则没有天然业务键,也不要求 IT 填编码。 */
|
||||
create table dbo.s_rule (
|
||||
b_id bigint not null, -- 雪花主键(新增时前端经 /data/nextid 取号)
|
||||
b_scope_type varchar(20) not null, -- module / relation(挂载范围)
|
||||
b_scope_id varchar(250) not null, -- module=模块编码;relation=源模块|源字段|目标模块|目标字段
|
||||
b_hook varchar(30) not null, -- delete.pre(一期只做这个),save.pre 留位
|
||||
b_predicate nvarchar(max) null, -- 空=引用规则;JSON={"kind":"dsl","expr":…}=勾条件;其余=SQL 文本
|
||||
b_message nvarchar(500) null, -- 提示文案(写 SQL 必填;勾条件可空,引擎按条件自动生成)
|
||||
b_canuse tinyint not null default 1, -- 是否启用(0/1)
|
||||
b_xh int not null default 0, -- 执行顺序(并列按 b_xh、b_id)
|
||||
b_created_by varchar(50) null, -- 审计列由服务端维护,配置界面不提交
|
||||
b_created_at datetime2 null,
|
||||
b_updated_by varchar(50) null,
|
||||
b_updated_at datetime2 null,
|
||||
primary key (b_id)
|
||||
);
|
||||
/* 3. 历史 'archive' 阶段一不支持:归一为 'none'(不处理、不保护),
|
||||
避免删除执行器读到未知处置值。空值与非法值同样归一,保证值域收敛。 */
|
||||
update dbo.s_relation
|
||||
set b_on_delete = 'none'
|
||||
where b_on_delete is null
|
||||
or b_on_delete not in ('restrict', 'cascade', 'none');
|
||||
GO
|
||||
|
||||
create index ix_s_rule_scope
|
||||
on dbo.s_rule (b_scope_type, b_scope_id, b_hook, b_canuse, b_xh);
|
||||
GO
|
||||
/* 4. 删除 SQL 规则表。 */
|
||||
if object_id('dbo.s_delete_rule', 'U') is null
|
||||
begin
|
||||
create table dbo.s_delete_rule (
|
||||
b_id bigint not null, -- 雪花主键(新增时前端经 /data/nextid 取号)
|
||||
b_module_id varchar(50) not null, -- 规则所属数据模块编码(对应 s_module.b_id)
|
||||
b_sql nvarchar(max) not null, -- 只读查询 SQL,用 :ids 标记本次待删 ID 集合
|
||||
b_message nvarchar(500) null, -- 删除失败时的提示文案(第一阶段固定文案)
|
||||
b_canuse tinyint not null default 1, -- 是否启用(0/1)
|
||||
b_xh int not null default 0, -- 执行顺序(并列按 b_xh、b_id)
|
||||
b_created_by varchar(50) null, -- 审计列由服务端维护,配置界面不提交
|
||||
b_created_at datetime2 null,
|
||||
b_updated_by varchar(50) null,
|
||||
b_updated_at datetime2 null,
|
||||
primary key (b_id)
|
||||
);
|
||||
end
|
||||
GO
|
||||
|
||||
if not exists (
|
||||
select 1 from sys.indexes
|
||||
where name = 'ix_s_delete_rule_module'
|
||||
and object_id = object_id('dbo.s_delete_rule')
|
||||
)
|
||||
begin
|
||||
create index ix_s_delete_rule_module
|
||||
on dbo.s_delete_rule (b_module_id, b_canuse, b_xh);
|
||||
end
|
||||
GO
|
||||
|
||||
/* 5. 旧表 s_rule 的处置。
|
||||
已确认库内 s_rule 无配置数据,可直接重建;此处刻意不 drop,
|
||||
避免脚本误伤可能存在的历史配置。确认无数据后手工执行:
|
||||
|
||||
drop table if exists dbo.s_rule;
|
||||
|
||||
若库中确实存在规则数据,需先迁移:
|
||||
- b_scope_type='module' 且 b_predicate 为 SQL 文本 → 写入 s_delete_rule
|
||||
(b_module_id = b_scope_id,b_sql = b_predicate);
|
||||
- b_scope_type='relation'(引用规则)→ 置该关系 s_relation.b_on_delete='restrict';
|
||||
- b_predicate 为 JSON 勾条件的数据无法自动转换,需人工改写为等价 SQL。 */
|
||||
@@ -0,0 +1,22 @@
|
||||
/* ============================================================================
|
||||
删除废弃表 s_rule
|
||||
----------------------------------------------------------------------------
|
||||
背景:删除策略重构(FMS删除策略重构设计.md v1.2)用 s_delete_rule 取代了
|
||||
旧的泛化规则表 s_rule。s_rule 已无任何读取方(前端旧概念、后端引用均已移除),
|
||||
且经核实库中行数为 0,可直接删除。
|
||||
|
||||
执行前已确认:
|
||||
- catalog = FMS(RunSqlFile 自带校验)
|
||||
- s_rule 行数 = 0
|
||||
- s_delete_rule 已存在(新表就位)
|
||||
|
||||
执行:fms-api 目录下
|
||||
java -cp "tools/migration/mssql-jdbc-13.4.0.jre11.jar" tools/migration/RunSqlFile.java \
|
||||
../sql/fms_drop_s_rule.sql
|
||||
============================================================================ */
|
||||
|
||||
if object_id('dbo.s_rule', 'U') is not null
|
||||
begin
|
||||
drop table dbo.s_rule;
|
||||
end
|
||||
GO
|
||||
@@ -0,0 +1,17 @@
|
||||
/* 冒烟测试数据:主单 2 条,明细 3 条(O1 有 2 条明细,O2 有 1 条) */
|
||||
delete from dbo.smoke_order_item;
|
||||
GO
|
||||
delete from dbo.smoke_order;
|
||||
GO
|
||||
|
||||
insert into dbo.smoke_order (b_id, b_no, b_status) values ('SO-1', N'单号一', 'draft');
|
||||
GO
|
||||
insert into dbo.smoke_order (b_id, b_no, b_status) values ('SO-2', N'单号二', 'audited');
|
||||
GO
|
||||
|
||||
insert into dbo.smoke_order_item (b_item_id, b_order_id, b_name) values ('SI-1', 'SO-1', N'明细1');
|
||||
GO
|
||||
insert into dbo.smoke_order_item (b_item_id, b_order_id, b_name) values ('SI-2', 'SO-1', N'明细2');
|
||||
GO
|
||||
insert into dbo.smoke_order_item (b_item_id, b_order_id, b_name) values ('SI-3', 'SO-2', N'明细3');
|
||||
GO
|
||||
@@ -0,0 +1,63 @@
|
||||
/* ============================================================================
|
||||
删除策略冒烟测试夹具(可重复执行)
|
||||
----------------------------------------------------------------------------
|
||||
建一对专用临时业务表 + 模块配置 + 删除规则,用于验证删除引擎:
|
||||
smoke_order 主单(b_id varchar 业务键)
|
||||
smoke_order_item 明细(b_item_id 主键,b_order_id 外键指向主单)
|
||||
|
||||
覆盖场景:
|
||||
1. cascade:删主单连带删明细
|
||||
2. restrict:明细被引用时拒绝删主单
|
||||
3. SQL 规则:命中即整批拒绝
|
||||
4. direct:按表直删
|
||||
|
||||
清理见 smoke_delete_teardown.sql。
|
||||
============================================================================ */
|
||||
|
||||
if object_id('dbo.smoke_order_item', 'U') is null
|
||||
begin
|
||||
create table dbo.smoke_order_item (
|
||||
b_item_id varchar(50) not null primary key,
|
||||
b_order_id varchar(50) not null,
|
||||
b_name nvarchar(100) null
|
||||
);
|
||||
end
|
||||
GO
|
||||
|
||||
if object_id('dbo.smoke_order', 'U') is null
|
||||
begin
|
||||
create table dbo.smoke_order (
|
||||
b_id varchar(50) not null primary key,
|
||||
b_no nvarchar(50) null,
|
||||
b_status varchar(20) null
|
||||
);
|
||||
end
|
||||
GO
|
||||
|
||||
/* 模块配置:主单 */
|
||||
if not exists (select 1 from dbo.s_module where b_id = 'smoke_order')
|
||||
begin
|
||||
insert into dbo.s_module (b_id, b_parent_id, b_depth, b_path, b_name, b_module_type, b_view_table, b_save_table, b_key_field, b_canuse, b_xh)
|
||||
values ('smoke_order', null, 0, 'smoke_order', N'冒烟测试主单', 'data', 'smoke_order', 'smoke_order', 'b_id', 1, 9001);
|
||||
end
|
||||
GO
|
||||
|
||||
/* 模块配置:明细 */
|
||||
if not exists (select 1 from dbo.s_module where b_id = 'smoke_order_item')
|
||||
begin
|
||||
insert into dbo.s_module (b_id, b_parent_id, b_depth, b_path, b_name, b_module_type, b_view_table, b_save_table, b_key_field, b_canuse, b_xh)
|
||||
values ('smoke_order_item', null, 0, 'smoke_order_item', N'冒烟测试明细', 'data', 'smoke_order_item', 'smoke_order_item', 'b_item_id', 1, 9002);
|
||||
end
|
||||
GO
|
||||
|
||||
/* 关系:明细 → 主单,many_to_one。
|
||||
按设计 §3.2,many_to_one 的外键在源字段:源字段 b_order_id 是明细表里的外键列,
|
||||
目标字段 b_id 是主单被引用的列。删除主单时,明细(引用方)被 cascade 连带删除。 */
|
||||
delete from dbo.s_relation where b_source_module_id = 'smoke_order_item' and b_target_module_id = 'smoke_order';
|
||||
GO
|
||||
|
||||
insert into dbo.s_relation
|
||||
(b_source_module_id, b_source_field, b_target_module_id, b_target_field, b_relation_type, b_on_delete, b_canuse, b_xh)
|
||||
values
|
||||
('smoke_order_item', 'b_order_id', 'smoke_order', 'b_id', 'many_to_one', 'cascade', 1, 10);
|
||||
GO
|
||||
@@ -0,0 +1,40 @@
|
||||
/* ============================================================================
|
||||
删除策略冒烟测试夹具:清理(可重复执行,表不存在也能跑通)
|
||||
----------------------------------------------------------------------------
|
||||
注意两点,都是实测踩出来的:
|
||||
1. 关系行必须按双向清理:冒烟会临时造反向关系(环路场景 smoke_order → smoke_order_item),
|
||||
只删一个方向会留下指向已 drop 表的孤儿行。
|
||||
2. 业务表的 delete 必须用 object_id 守卫:清理可重入,表已 drop 时直接 delete 会报
|
||||
Invalid object name,而 RunSqlFile 是单事务、一批失败整体回滚,
|
||||
会导致整个清理静默失效(前面几批的删除也被回滚)。
|
||||
============================================================================ */
|
||||
|
||||
delete from dbo.s_delete_rule where b_module_id in ('smoke_order', 'smoke_order_item');
|
||||
GO
|
||||
|
||||
/* 关系行:双向清理,避免孤儿关系 */
|
||||
delete from dbo.s_relation
|
||||
where b_source_module_id in ('smoke_order', 'smoke_order_item')
|
||||
or b_target_module_id in ('smoke_order', 'smoke_order_item');
|
||||
GO
|
||||
|
||||
delete from dbo.s_module where b_id in ('smoke_order', 'smoke_order_item');
|
||||
GO
|
||||
|
||||
if object_id('dbo.smoke_order_item', 'U') is not null
|
||||
begin
|
||||
delete from dbo.smoke_order_item;
|
||||
end
|
||||
GO
|
||||
|
||||
if object_id('dbo.smoke_order', 'U') is not null
|
||||
begin
|
||||
delete from dbo.smoke_order;
|
||||
end
|
||||
GO
|
||||
|
||||
drop table if exists dbo.smoke_order_item;
|
||||
GO
|
||||
|
||||
drop table if exists dbo.smoke_order;
|
||||
GO
|
||||
Reference in new issue
Block a user