diff --git a/crates/erp-plugin/src/data_service.rs b/crates/erp-plugin/src/data_service.rs index 3053461..8dba347 100644 --- a/crates/erp-plugin/src/data_service.rs +++ b/crates/erp-plugin/src/data_service.rs @@ -262,6 +262,65 @@ impl PluginDataService { _event_bus: &EventBus, ) -> AppResult<()> { let info = resolve_entity_info(plugin_id, entity_name, tenant_id, db).await?; + + // 解析 entity schema 获取 relations + let entity_def: crate::manifest::PluginEntity = + serde_json::from_value(info.schema_json.clone()) + .map_err(|e| AppError::Internal(format!("解析 entity schema 失败: {}", e)))?; + + let manifest_id = resolve_manifest_id(plugin_id, tenant_id, db).await?; + + // 处理级联关系 + for relation in &entity_def.relations { + let rel_table = DynamicTableManager::table_name(&manifest_id, &relation.entity); + let fk = sanitize_identifier(&relation.foreign_key); + + match relation.on_delete { + crate::manifest::OnDeleteStrategy::Restrict => { + let check_sql = format!( + "SELECT 1 as chk FROM \"{}\" WHERE data->>'{}' = $1 AND tenant_id = $2 AND deleted_at IS NULL LIMIT 1", + rel_table, fk + ); + #[derive(FromQueryResult)] + struct RefCheck { chk: Option } + let has_ref = RefCheck::find_by_statement(Statement::from_sql_and_values( + sea_orm::DatabaseBackend::Postgres, + check_sql, + [id.to_string().into(), tenant_id.into()], + )).one(db).await?; + if has_ref.is_some() { + return Err(AppError::Validation(format!( + "存在关联的 {} 记录,无法删除", + relation.entity + ))); + } + } + crate::manifest::OnDeleteStrategy::Nullify => { + let nullify_sql = format!( + "UPDATE \"{}\" SET data = jsonb_set(data, '{{{}}}', 'null'), updated_at = NOW() WHERE data->>'{}' = $1 AND tenant_id = $2 AND deleted_at IS NULL", + rel_table, fk, fk + ); + db.execute(Statement::from_sql_and_values( + sea_orm::DatabaseBackend::Postgres, + nullify_sql, + [id.to_string().into(), tenant_id.into()], + )).await?; + } + crate::manifest::OnDeleteStrategy::Cascade => { + let cascade_sql = format!( + "UPDATE \"{}\" SET deleted_at = NOW(), updated_at = NOW() WHERE data->>'{}' = $1 AND tenant_id = $2 AND deleted_at IS NULL", + rel_table, fk + ); + db.execute(Statement::from_sql_and_values( + sea_orm::DatabaseBackend::Postgres, + cascade_sql, + [id.to_string().into(), tenant_id.into()], + )).await?; + } + } + } + + // 软删除主记录 let (sql, values) = DynamicTableManager::build_delete_sql(&info.table_name, id, tenant_id); db.execute(Statement::from_sql_and_values(