# 在线表单与第三方数据库

## 架构

- **平台库**（`db_config=default`）：`FormMeta`、权限、字典、`core_user` / 省市区等元数据表。
- **业务库**（`FormMeta.db_config` 为连接 code）：表单主表/子表 CRUD、导入导出。

业务逻辑统一由 `FormDataService` + `DynamicSQLBuilder` 处理；仅在 `create_form_data_adapter()` 分叉：

- `default` → `PlatformSessionAdapter`（SQLAlchemy `AsyncSession`）
- 其他 code → `ExternalConnectionAdapter`（`DatabaseManager` Handler + 字面量参数 SQL）

## 与 default 对齐的近期改动

| 项 | 说明 |
|----|------|
| PostgreSQL 多库 | 外部 PG 执行/事务时按 `main_table_database` 或子表 `table_database` 切换连接库（`_table_exec_database`） |
| 子表跨库 | 子表 CRUD/查询传入子表 `table_database`，不再一律使用主表库名 |
| 表单选择器筛选 | 列表按显示名筛选时，`relation_type=form_data` 会查关联表单业务表并转为 ID |
| 导入提交粒度 | **default**：单事务内分批 `db.commit()`；**第三方**：每批数据独立 Handler 事务，成功批次已提交、失败批次不影响已成功批次 |
| 库名校验 | `validate_form_tables` 返回 `database_warnings`（MySQL 跨库、PG 未配默认库等） |

## 回归检查清单

| 用例 | 说明 |
|------|------|
| CRUD 主+子 | 外部库新增/编辑/删除含子表 |
| PG 多 database | 连接无 default_database 时依赖表单 `main_table_database` |
| 用户/部门/省市区 | 列表展示与筛选（始终查平台库 `core_*`） |
| 关联他表 | 同连接与跨连接 formData；按名称列表筛选 |
| 导入 | 覆盖 / 仅新增 / upsert；第三方分批提交 |
| 发布 | `validate_form_tables`（含 `database_warnings`） |

## 限制

- 系统连接（`is_system`）不可写入表单业务表。
- 跨方言导入自动建表会拒绝（需同引擎或手工建表）；导入预检查返回 `target_db_type`，前端与导出 JSON 中的 `export_db_type` 比对并提示。
- 游标分页：SQL Server / Oracle 使用等值前缀 + OR 链；PostgreSQL / MySQL 使用行值比较。
- **SQL Server 中文**：字符串列须为 `NVARCHAR` / `NCHAR` / `NVARCHAR(MAX)`，勿用 `VARCHAR`/`CHAR`/`TEXT`，否则中文会变成 `?`。新建表已默认映射为 N* 类型；已有表需 `ALTER COLUMN` 迁移。
- **Oracle**：连接使用 service name（`default_database` / 连接配置），不按 PostgreSQL 方式切换 database；schema 一般为当前用户。
- **MySQL**：表名通过 `` `database`.`table` `` 限定；连接默认库与 `main_table_database` 不一致时需账号具备跨库权限。
- **平台关联表**：用户/部门/字典/省市区等仅查平台库；业务表请勿配置为 `core_user` 等平台表名。
- **单请求多 PG database**：主表与子表若在不同 PostgreSQL database，无法在同一 Handler 事务中原子提交，应保证主/子表在同一库或接受非原子语义。
