-- ===================================================================================== -- 1.0.506 · S0 MASTER DATA PLATFORM · PHASE 2 · BATCH 4 -- -- 目标:在 Phase 1 已验证的 S0Dim 通用框架上扩展两个 C1 维度,**只加 Definition,不加服务**。 -- EmployeeMaster → mdp_stg_s0_employee → dim_employee -- LineMaster → mdp_stg_s0_line → dim_line -- -- 本批边界(与 Phase 1 一致): -- · 不建、不改、不删共享表 mdp_stg_location / mdp_stg_employee / mdp_stg_line -- (后两张属 DOPDEMORQ,当前 0 行,但不是 S0 的 authority —— 故另建 S0 专用 stg) -- · 不写 mdp_source / mdp_field_mapping;不碰 mdp_std_item / mdp_std_supplier -- · 不动 S1–S9 既有对象、不动 S0 CRUD、不动前端 -- -- 取号:开发期用 WIP 名,提交那刻按 origin/master 实际最大号 +1 改名为 1.0..sql -- (verify 脚本必须同批同号改名,AutoVersionUpdate 用 Path.ChangeExtension 配对)。 -- -- 租户契约(P0,实测依据): -- · Employee 身份 = tenant_id + Employee (Domain / company / factory 均为属性,非身份) -- · Line 身份 = tenant_id + Line (Domain / company / factory 均为属性,非身份) -- -- 身份口径按「当前业务证据优先」重判(2026-09-07 Semantic Gate),**不继承旧物理唯一键**: -- · Employee CRUD 查重 = tenant + FactoryRefId + Employee,不含 Domain;而 FactoryRefId 由 -- AdoS0OrgScope.ResolveAsync 仅按租户解析并强制 stamp ⇒ 等价于 tenant + Employee。 -- · Employee 真实 consumer 一律 `ON p.Buyer=e.Employee AND e.tenant_id=p.tenant_id`(5 处),无一处用 Domain。 -- · Line CRUD 无任何查重守卫;consumer GetLinesAsync 只用 (TenantId, Line)。 -- · 数据实测:tenant+Employee 租户内重复=0;Line 四个候选租户内重复全部=0, -- 且每个租户在 LineMaster 只有 1 个 Domain / 1 个 company / 1 个 factory ⇒ 租户内常量、零区分力。 -- · 租户仍必须入身份:Employee 跨租户碰撞 19 组 / 38 行,Line 20 组 / 80 行; -- Domain 与 factory_ref_id=1000 均被多租户复用,都不具备隔离能力。 -- ===================================================================================== -- ── 一、S0 专用贴源表(2 张)────────────────────────────────────────────────────── -- UK 刻意包含 source_system:共享表 mdp_stg_location 的 UK 不含它,导致同名源表在不同源 -- 之间串键(Phase 1 已实证)。S0 自有表一律补上,即使当前只有一个源。 CREATE TABLE IF NOT EXISTS `mdp_stg_s0_employee` ( `id` bigint NOT NULL AUTO_INCREMENT, `tenant_id` bigint NOT NULL DEFAULT 0, `factory_id` bigint DEFAULT NULL, `source_system` varchar(50) NOT NULL DEFAULT 'AIDOPDEV_MYSQL', `source_table` varchar(100) NOT NULL, `source_row_id` varchar(100) NOT NULL, `source_biz_key` varchar(300) DEFAULT NULL, `sync_batch_id` varchar(100) NOT NULL, `sync_time` datetime NOT NULL, `process_status` varchar(20) NOT NULL DEFAULT 'PENDING', `raw_data` json NOT NULL, `process_message` varchar(500) DEFAULT NULL, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_stg_s0_employee` (`tenant_id`,`source_system`,`source_table`,`source_row_id`), KEY `idx_stg_s0_employee_biz` (`source_biz_key`), KEY `idx_stg_s0_employee_batch` (`tenant_id`,`sync_batch_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='S0 主数据贴源:雇员(源 EmployeeMaster)'; CREATE TABLE IF NOT EXISTS `mdp_stg_s0_line` ( `id` bigint NOT NULL AUTO_INCREMENT, `tenant_id` bigint NOT NULL DEFAULT 0, `factory_id` bigint DEFAULT NULL, `source_system` varchar(50) NOT NULL DEFAULT 'AIDOPDEV_MYSQL', `source_table` varchar(100) NOT NULL, `source_row_id` varchar(100) NOT NULL, `source_biz_key` varchar(300) DEFAULT NULL, `sync_batch_id` varchar(100) NOT NULL, `sync_time` datetime NOT NULL, `process_status` varchar(20) NOT NULL DEFAULT 'PENDING', `raw_data` json NOT NULL, `process_message` varchar(500) DEFAULT NULL, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_stg_s0_line` (`tenant_id`,`source_system`,`source_table`,`source_row_id`), KEY `idx_stg_s0_line_biz` (`source_biz_key`), KEY `idx_stg_s0_line_batch` (`tenant_id`,`sync_batch_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='S0 主数据贴源:生产线(源 LineMaster)'; -- ── 二、维度表(2 张)──────────────────────────────────────────────────────────── -- tenant_id 一律 NOT NULL 且为唯一键首列;FULL REPLACE 按 tenant_id 分区删改。 -- -- 舍弃的源列(明确记录,避免下次误以为漏了): -- EmployeeMaster:Sex / Phone / Email / BirthDate / MaritalStatus / City / Country / -- BusinessPhone / CarId / DefaultWorkLocation —— 个人信息或无主数据语义, -- 维度层不承载 PII;CreateUser/CreateTime/UpdateUser/RecID —— 审计列,非主数据属性。 -- LineMaster: line_describe(恒空影子列,真列是 Describe)· PickingLocation(0/169 填充) · -- location3(0/169) · VLocation / MidLocation / location2(各 28/169, -- 三个无标准语义的备用库位槽,含义未经业务确认)· CreateUser/CreateTime/UpdateUser/RecID。 CREATE TABLE IF NOT EXISTS `dim_employee` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '技术行号;每轮 FULL 重建即变,禁止外部引用', `tenant_id` bigint NOT NULL COMMENT '租户', `company_id` bigint NOT NULL COMMENT '← $.company_ref_id;属性,不入身份', `factory_id` bigint NOT NULL COMMENT '← $.factory_ref_id;属性,不入身份(1000 被多租户共用,无隔离能力)', `employee_code` varchar(100) NOT NULL COMMENT '工号(**唯一业务键**)← $.Employee', `domain_code` varchar(50) NOT NULL COMMENT 'ATTRIBUTE ← $.Domain;仅供部门父连接与引用校验,**不是身份**', `employee_name` varchar(200) DEFAULT NULL COMMENT '← $.Name', `department_code` varchar(100) DEFAULT NULL COMMENT '← $.Department;自由文本软引用 dim_department,无 DB FK;NULL=未分配(不算孤儿)', `job_title` varchar(100) DEFAULT NULL COMMENT '← $.JobTitle', `work_center_code` varchar(100) DEFAULT NULL COMMENT '← $.WorkCtr;按业务键引用 dim_work_center,无 DB FK', `employment_status` varchar(50) DEFAULT NULL COMMENT '← $.EmploymentStatus', `date_employed` datetime DEFAULT NULL COMMENT '← $.DateEmployed', `date_terminated` datetime DEFAULT NULL COMMENT '← $.DateTerminated', `sys_user_id` bigint DEFAULT NULL COMMENT '← $.sys_user_id;稀疏(源 7/1105 非空)。**属性,绝不参与业务键**', `is_active` tinyint(1) NOT NULL COMMENT '源 IsActive 透传(raw_data 中为 JSON BOOLEAN)', `source_system` varchar(50) NOT NULL, `source_biz_key` varchar(300) NOT NULL COMMENT '回溯 staging 用', `source_updated_at` datetime DEFAULT NULL COMMENT '← $.UpdateTime;源 97% 非空,允许 NULL,不得回填假时间', `sync_batch_id` varchar(64) NOT NULL, `sync_time` datetime NOT NULL, `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_dim_employee` (`tenant_id`,`employee_code`), KEY `idx_dim_employee_batch` (`sync_batch_id`), KEY `idx_dim_employee_dept` (`tenant_id`,`domain_code`,`department_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='S0 主数据维度:雇员。源 EmployeeMaster,FULL REPLACE。'; CREATE TABLE IF NOT EXISTS `dim_line` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '技术行号;每轮 FULL 重建即变,禁止外部引用', `tenant_id` bigint NOT NULL COMMENT '租户', `company_id` bigint NOT NULL COMMENT 'LEGACY_SCOPE ← $.company_ref_id;f(tenant),**不是身份**', `factory_id` bigint NOT NULL COMMENT 'LEGACY_SCOPE ← $.factory_ref_id;f(tenant),**不是身份**。⚠️ 绝不可设进 MdpPullContext.FactoryId,见 I-015', `line_code` varchar(100) NOT NULL COMMENT '产线编码(**唯一业务键**)← $.Line', `domain_code` varchar(50) NOT NULL COMMENT 'LEGACY_SCOPE ← $.Domain;租户内常量,**不是身份**', `line_name` varchar(255) DEFAULT NULL COMMENT '← $.Describe(真列;同表 line_describe 恒空,是影子列)', `line_type` varchar(50) DEFAULT NULL COMMENT '← $.LineType', `line_category` varchar(50) DEFAULT NULL COMMENT '← $.LineCategory', `workshop` varchar(50) DEFAULT NULL COMMENT '← $.Workshop', `location_code` varchar(50) DEFAULT NULL COMMENT '← $.Location;按业务键软引用 dim_location,无 DB FK', `is_active` tinyint(1) NOT NULL COMMENT '源 IsActive 透传', `source_system` varchar(50) NOT NULL, `source_biz_key` varchar(300) NOT NULL COMMENT '回溯 staging 用', `source_updated_at` datetime DEFAULT NULL COMMENT '← $.UpdateTime;源 100% 非空', `sync_batch_id` varchar(64) NOT NULL, `sync_time` datetime NOT NULL, `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_dim_line` (`tenant_id`,`line_code`), KEY `idx_dim_line_batch` (`sync_batch_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='S0 主数据维度:生产线。源 LineMaster,FULL REPLACE。'; -- ── 三、mdp_entity 入站配置(2 条,全 FULL)────────────────────────────────────── -- -- · sync_mode 必须 FULL、incr_column 必须 NULL:Phase 2 既定策略。 -- 即便 Employee UpdateTime 97%、Line 100%,也不切 INCR —— -- 留 incr_column 会让 BuildSelectSql 生成 "col > @cursor",使水位为 NULL 的行永久不可达 -- (Employee 实测有 29 行 UpdateTime 为 NULL)。 -- · biz_key_expr 是【源物理列名】逗号列表,须与 Definition.SourceBizKeyColumns 逐字一致, -- 否则 S0DimMaterializer.AssertEntityContractAsync 会当场报配置漂移。 -- · batch_size 必须大于单租户最大行数(Employee 最大 613、Line 最大 109),5000 余量充足。 SET @src_id = (SELECT `id` FROM `mdp_source` WHERE `source_code` = 'AIDOPDEV_MYSQL' LIMIT 1); INSERT INTO `mdp_entity` (`tenant_id`,`source_id`,`entity_code`,`entity_name`,`entity_type`, `source_table_name`,`target_table_name`,`sync_mode`,`incr_column`,`batch_size`, `biz_key_expr`,`status`,`create_time`,`update_time`) SELECT 0, @src_id, 'S0_EMPLOYEE', 'S0 雇员主数据入站', 'TABLE', 'EmployeeMaster', 'mdp_stg_s0_employee', 'FULL', NULL, 5000, 'Employee', 1, NOW(), NOW() WHERE @src_id IS NOT NULL AND NOT EXISTS (SELECT 1 FROM `mdp_entity` WHERE `entity_code` = 'S0_EMPLOYEE'); INSERT INTO `mdp_entity` (`tenant_id`,`source_id`,`entity_code`,`entity_name`,`entity_type`, `source_table_name`,`target_table_name`,`sync_mode`,`incr_column`,`batch_size`, `biz_key_expr`,`status`,`create_time`,`update_time`) SELECT 0, @src_id, 'S0_LINE', 'S0 生产线主数据入站', 'TABLE', 'LineMaster', 'mdp_stg_s0_line', 'FULL', NULL, 5000, 'Line', 1, NOW(), NOW() WHERE @src_id IS NOT NULL AND NOT EXISTS (SELECT 1 FROM `mdp_entity` WHERE `entity_code` = 'S0_LINE'); -- ── 回滚(注释,非可执行;执行前请确认无消费者)────────────────────────────────── -- DROP TABLE IF EXISTS `dim_line`; -- DROP TABLE IF EXISTS `dim_employee`; -- DROP TABLE IF EXISTS `mdp_stg_s0_line`; -- DROP TABLE IF EXISTS `mdp_stg_s0_employee`; -- DELETE FROM `mdp_entity` WHERE `tenant_id` = 0 AND `entity_code` IN ('S0_EMPLOYEE','S0_LINE');