Files
sunvpy-docs/docs/content/45-shu-ju-ku-geng-xin-jie-kou.md
2026-04-10 13:47:53 +08:00

1136 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
数据库更新接口是 SunvStation GIS 系统中用于管理和执行数据库操作的核心组件,提供了从底层 SQL 执行到高级对象同步的完整功能层次。该接口采用 SWIG 封装技术将 C++ 核心功能暴露给 Python实现了高性能的数据库操作与 Python 脚本的无缝集成。
## 架构概览
数据库更新接口采用分层架构设计,从底层的直接数据库操作到上层的业务对象管理,提供了不同抽象级别的接口以满足不同场景的需求。
```mermaid
graph TB
subgraph "应用层"
GeoEditMixin[GeoEditMixin<br/>地理编辑混合类]
SSProcess[SSProcessManager<br/>流程管理器]
end
subgraph "业务逻辑层"
SSDbScript[SSDbScript<br/>GIS数据库脚本接口]
DataXScript[DataXScript<br/>数据交换接口]
end
subgraph "数据访问层"
Database[Database<br/>数据库抽象接口]
StringArray[StringArray<br/>字符串数组容器]
AttrList[AttrList<br/>属性列表]
FeatureList[FeatureList<br/>地物列表]
end
subgraph "C++核心层"
_PySSGisDBUpdate[_PySSGisDBUpdate<br/>C++GIS数据库模块]
_PySSDatabase[_PySSDatabase<br/>C++数据库模块]
_PySSDataX[_PySSDataX<br/>C++数据交换模块]
end
GeoEditMixin --> SSDbScript
SSProcess --> GeoEditMixin
SSDbScript --> _PySSGisDBUpdate
DataXScript --> _PySSDataX
Database --> _PySSDatabase
SSDbScript --> Database
Database --> StringArray
Database --> AttrList
Database --> FeatureList
```
**核心设计原则**:该架构通过多层抽象,实现了从底层 SQL 执行到高级对象操作的完整覆盖同时保持了各层之间的清晰边界。SWIG 封装机制确保了 Python 接口与 C++ 实现的透明交互,[7-swig-feng-zhuang-ji-zhi-shuo-ming](7-swig-feng-zhuang-ji-zhi-shuo-ming) 详细解释了这一机制的实现原理。
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L1-L493), [PySSDatabase.py](PySSDatabase.py#L1-L1643)
## SSDbScript 核心接口
SSDbScript 是 GIS 数据库更新操作的主要接口类,提供了从服务器数据库到本地数据库的数据同步、地物属性更新、表记录管理等完整功能集。
### 连接与认证管理
SSDbScript 支持多种认证模式,包括基础用户认证和角色认证,确保数据库操作的安全性和权限控制。
```mermaid
sequenceDiagram
participant Python
participant SSDbScript
participant Database
participant SDEServer
Python->>SSDbScript: SSDbScript()
Python->>SSDbScript: login(userName, password)
SSDbScript->>Database: 验证凭证
Database->>SDEServer: 建立连接
SDEServer-->>Database: 连接成功
Database-->>SSDbScript: 认证通过
SSDbScript-->>Python: 返回 True
Python->>SSDbScript: connectToTablespace(name)
SSDbScript->>Database: 切换工作空间
Database-->>SSDbScript: 工作空间就绪
SSDbScript-->>Python: 返回 True
Note over Python,SDEServer: 执行数据库操作...
Python->>SSDbScript: logout()
SSDbScript->>Database: 关闭连接
Database->>SDEServer: 释放资源
SSDbScript-->>Python: 会话结束
```
**连接方法**
| 方法 | 参数 | 说明 |
|------|------|------|
| `login()` | `userName, password` | 基础用户认证 |
| `login1()` | `userName, password, roleName` | 带角色的用户认证 |
| `logout()` | 无 | 断开数据库连接 |
| `connectToTablespace()` | `tablespaceName` | 连接到指定工作空间 |
| `getTablespaceNameList()` | `tablespaceType` | 获取工作空间名称列表 |
| `getUserRoleNameList()` | 无 | 获取用户角色列表 |
| `resetCurrentRoleName()` | `roleName` | 重置当前用户角色 |
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L78-L100)
### 数据下载接口
数据下载接口支持从服务器 SDE 数据库下载指定范围或指定条件的数据到本地数据库,提供了灵活的数据提取策略。
```python
# 示例:按区域范围下载指定图层数据
from sunvpy.PySSGisDBUpdate import SSDbScript
db_script = SSDbScript()
db_script.login("username", "password")
# 定义下载区域坐标范围
region_coords = [(116.3, 39.9), (116.5, 39.9),
(116.5, 40.0), (116.3, 40.0)]
# 下载指定图层的当前版本数据
result = db_script.downloadDBToLocalDB(
workspace_handle, # 工作空间句柄
region_coords, # 区域坐标
"RoadLayer", # 图层名称
"code > 100", # WHERE 条件
False # 是否下载历史版本
)
print(f"下载结果: {'成功' if result else '失败'}")
```
**下载方法变体**
| 方法 | 场景 | 关键参数 |
|------|------|----------|
| `downloadDBToLocalDB()` | 按坐标范围和图层下载 | `regionCoords`, `layerName`, `whereClause`, `isHistory` |
| `downloadDBToLocalDB1()` | 按 GUID 区域下载 | `regionGUID`, `isUpdateDownload` |
| `downloadDBToLocalDB2()` | 按 GUID 和图层下载 | `regionGUID`, `layerName`, `isUpdateDownload` |
| `downloadDBToLocalDB3()` | 带 GUID 列表的批量下载 | `regionGUID`, `byteObjList` |
| `downloadDBToLocalDB4()` | 带坐标列表的批量下载 | `regionCoords`, `byteObjList` |
| `downloadDBToLocalDB5()` | 按 GeoID 下载 | `regionGeoID`, `layerName` |
**参数说明**
- `workspaceHandle`:工作空间句柄,通过 `map.getWorkspaceHandle()` 获取
- `regionCoords`:坐标范围,使用 `DblRect` 或坐标点列表表示
- `regionGUID`/`regionGeoID`:区域的唯一标识符
- `layerName`:目标图层名称
- `whereClause`SQL WHERE 条件表达式
- `isHistory`:是否下载历史版本数据
- `isUpdateDownload`:是否为增量下载模式
- `byteObjList`:对象 GUID 字节数组列表,用于指定特定对象
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L102-L122)
### 数据上传接口
数据上传接口将本地数据库中的修改同步到服务器 SDE 数据库,支持不同的更新策略。
| updateMode 值 | 说明 | 适用场景 |
|---------------|------|----------|
| 0 | 仅新增 | 添加新对象到服务器 |
| 1 | 仅更新 | 更新服务器上已存在的对象 |
| 2 | 新增+更新 | 默认模式,同时处理新增和更新 |
| 3 | 删除 | 删除服务器上的对象 |
```python
# 示例:上传本地修改到服务器
result = db_script.uploadLocalDBToDB(
workspace_handle, # 工作空间句柄
"RoadLayer", # 目标图层
2 # 更新模式:新增+更新
)
if result:
print("数据上传成功")
else:
print(f"上传失败: {db_script.m_strLogInfos}")
```
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L123-L125)
### 地物操作接口
地物操作接口提供了对单个地物的增删改查功能,支持复杂的查询条件和跨图层操作。
**地物复制**
```python
# 在同一工作空间内复制地物
result = db_script.copyFeatureToNewLayer(
workspace_handle, # 源工作空间
"SourceLayer", # 源图层
"TargetLayer", # 目标图层
"code = 150", # 复制条件
True # 是否删除目标图层中旧对象
)
# 跨工作空间复制地物
result = db_script.copyFeatureToNewLayer1(
workspace_handle_src, # 源工作空间
"SourceLayer", # 源图层
workspace_handle_tag, # 目标工作空间
"TargetLayer", # 目标图层
"status = 1" # 复制条件
)
```
**地物删除与更新**
```python
# 删除满足条件的地物
result = db_script.deleteFeature(
workspace_handle,
"RoadLayer",
"age > 10" # 删除条件
)
# 更新指定地物的属性
result = db_script.updateFeatureAttr(
workspace_handle,
"RoadLayer",
"{guid-of-feature}", # 地物 GUID
"code,status,name", # 要更新的字段列表(逗号分隔)
"200,1,UpdatedRoad" # 对应的字段值(逗号分隔)
)
```
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L142-L153), [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L155-L167)
### 表记录管理接口
表记录管理接口提供了对 SDE 数据库中自定义表的 CRUD 操作,支持动态表创建和复杂查询。
```mermaid
flowchart TD
A[表记录操作] --> B{操作类型}
B -->|创建| C[createSDEDBTable]
B -->|查询| D[searchSDEDBTableRecord]
B -->|新增| E[addSDEDBTableRecord]
B -->|修改| F[editSDEDBTableRecord]
B -->|删除| G[deleteSDEDBTableRecord]
B -->|自定义查询| H[customQuerySDETableRecord]
C --> C1[fieldInfos: 字段定义]
D --> D1[strCondition: WHERE 条件]
D --> D2[strOrderBy: 排序字段]
E --> E1[fields: 字段名列表]
E --> E2[values: 字段值列表]
F --> F1[strCondition: 更新条件]
G --> G1[strCondition: 删除条件]
H --> H1[dlgWidth/Height: 对话框尺寸]
```
**完整示例**
```python
from sunvpy.PySSGisDBUpdate import SSDbScript
db_script = SSDbScript()
# 1. 检查表是否存在
if not db_script.isExistSDEDBTable(workspace_handle, "MyCustomTable"):
# 2. 创建新表
field_infos = [
{"name": "id", "type": "INTEGER", "primary": True},
{"name": "name", "type": "VARCHAR(100)"},
{"name": "value", "type": "DOUBLE"},
{"name": "created_at", "type": "DATETIME"}
]
db_script.createSDEDBTable(workspace_handle, "MyCustomTable", field_infos)
# 3. 添加记录
fields = ["name", "value", "created_at"]
values = ["测试记录", 123.45, "2024-01-15 10:30:00"]
db_script.addSDEDBTableRecord(workspace_handle, "MyCustomTable", fields, values)
# 4. 查询记录
sel_fields = ["id", "name", "value"]
results = db_script.searchSDEDBTableRecord(
workspace_handle,
"MyCustomTable",
"value > 100", # WHERE 条件
sel_fields # 查询字段
)
# 5. 更新记录
update_fields = ["value"]
update_values = ["234.56"]
db_script.editSDEDBTableRecord(
workspace_handle,
"MyCustomTable",
"name = '测试记录'", # 更新条件
update_fields,
update_values
)
# 6. 删除记录
db_script.deleteSDEDBTableRecord(
workspace_handle,
"MyCustomTable",
"id < 1000" # 删除条件
)
```
**查询方法变体**
| 方法 | 特点 | 适用场景 |
|------|------|----------|
| `searchSDEDBTableRecord()` | 基础查询 | 简单条件查询 |
| `searchSDEDBTableRecord1()` | 支持排序和字段选择 | 需要指定排序和返回字段 |
| `customQuerySDETableRecord()` | 自定义查询对话框 | 交互式查询 |
| `searchFeatureAttr()` | 地物属性查询 | 查询地物属性信息 |
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L184-L211)
### 数据库同步接口
数据库同步接口支持在不同工作空间之间同步数据,包括全量同步和增量同步模式。
```python
# 全量同步指定图层
sync_layers = ["RoadLayer", "BuildingLayer", "WaterLayer"]
result = db_script.synchronousDatabase(
"PublicScheme", # 同步方案名称
workspace_handle_src, # 源工作空间
workspace_handle_tag, # 目标工作空间
sync_layers # 要同步的图层列表
)
# 带坐标转换脚本的增量同步
result = db_script.synchronousDatabase1(
"PublicScheme", # 同步方案
workspace_handle_src,
workspace_handle_tag,
sync_layers,
"TransformCoords(proj_src=4326, proj_dest=3857)" # 坐标转换脚本
)
# 带过滤条件的同步
result = db_script.synchronousDatabase2(
"PublicScheme",
workspace_handle_src,
workspace_handle_tag,
sync_layers,
"TransformCoords(...)", # 坐标转换脚本
"status = 1 AND code > 100" # 同步过滤条件
)
```
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L168-L183)
### 备份与恢复接口
备份接口支持完整备份和增量备份两种模式,确保数据安全。
```python
# 完整备份数据库到 EGDB 文件
result = db_script.backupDataToEgdb(
workspace_handle,
"D:/Backup/full_backup_20240115.egdb"
)
# 增量备份(仅备份变更数据)
result = db_script.incrementalBackupToEgdb(
workspace_handle,
"D:/Backup/incremental_20240115.egdb"
)
```
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L276-L281)
### 高级操作接口
高级接口提供了一些特殊场景下的操作功能,如创建更新区域、重置图形信息、按坐标下载对象等。
```python
# 创建道路更新区域
region_fields = ["region_id", "region_name", "created_by"]
region_values = [1001, "MainRoadUpdate", "admin"]
result = db_script.createRoadUpdateRegion(
workspace_handle,
"road_type = 1", # 道路筛选条件
"StartPoint", # 起点字段名
"EndPoint", # 终点字段名
50.0, # 缓冲距离(米)
True, # 是否处理关联道路
region_fields, # 区域字段
region_values # 区域值
)
# 重置图形信息
result = db_script.resetFeatureGraphicinfo(
workspace_handle,
"RoadLayer",
region_coords, # 重置区域
"color < 0" # 重置条件
)
# 按坐标下载对象
result = db_script.downloadObjByCoord(
workspace_handle,
"RoadLayer",
150, # 对象编码
[(x1, y1), (x2, y2), ...] # 搜索坐标
)
# 执行自定义 SQL
sql = "UPDATE MyTable SET value = value * 1.1 WHERE category = 'A'"
result = db_script.dbWorkspaceExecuteSQL(workspace_handle, sql)
```
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L240-L268), [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L283-L286)
## Database 底层数据库接口
Database 类提供了底层数据库访问接口支持事务管理、几何对象存取、SQL 执行等核心功能。与 SSDbScript 相比Database 接口更接近数据库底层,适合需要精细控制或高性能批量操作的场景。
### 连接与事务管理
Database 接口提供了完整的数据库连接生命周期管理和事务控制功能。
```mermaid
stateDiagram-v2
[*] --> Closed: 初始状态
Closed --> Open: openDatabase()
Open --> Closed: closeDatabase()
Open --> Transaction: beginTransaction()
Transaction --> Open: commitTransaction()
Transaction --> Open: rollbackTransaction()
state Open {
[*] --> Query: execute查询
[*] --> Modify: execute更新/插入/删除
Query --> [*]
Modify --> [*]
}
state Transaction {
[*] --> Executing: 执行操作
Executing --> Success: 操作成功
Executing --> Error: 操作失败
Success --> [*]
Error --> [*]
}
```
**连接方法**
```python
from sunvpy.PySSDatabase import Database
# 数据库连接通常通过工作空间获取
database = workspace.getDatabase()
# 事务处理示例
database.beginTransaction()
try:
# 执行多个操作
database.execute("UPDATE table1 SET value = value * 1.1")
database.execute("UPDATE table2 SET status = 1")
# 所有操作成功,提交事务
database.commitTransaction()
except Exception as e:
# 出现错误,回滚事务
database.rollbackTransaction()
print(f"事务失败: {e}")
```
**数据库信息查询**
```python
# 获取数据库类型
db_type = database.getDBType() # 返回 EpsDBType 枚举值
# 获取连接字符串
uri = database.getURI()
# 检查表和字段是否存在
if database.isTableExist("RoadLayer"):
if database.isFieldExist("RoadLayer", "code"):
print("表和字段都存在")
# 执行简单 SQL无结果集
result = database.execute("CREATE INDEX idx_code ON RoadLayer(code)")
```
Sources: [PySSDatabase.py](PySSDatabase.py#L244-L332)
### 几何对象存取
Geometry 存取是 Database 接口的核心功能,支持按区域、按 ID 列表、按 SQL 条件等多种方式加载几何对象。
```python
from sunvpy.PySSCore import GeoBaseList, BoundingRect
from sunvpy.PySSMap import DatasetDLG
# 获取数据集
dataset = map.getDataset("RoadLayer")
# 方式1按矩形区域加载
rect = BoundingRect()
rect.set(116.3, 39.9, 116.5, 40.0)
obj_list = GeoBaseList()
max_id = database.loadGeoObject(rect, dataset, 1, obj_list)
# 方式2按 ID 列表加载
from sunvpy.PySSCore import RowIdList
id_list = RowIdList()
for obj_id in [1001, 1002, 1003]:
id_list.append(obj_id)
obj_list = GeoBaseList()
max_id = database.loadGeoObject(id_list, dataset, 1, obj_list)
# 方式3按 SQL 查询加载
sql = "SELECT * FROM RoadLayer WHERE code > 100"
obj_list = GeoBaseList()
max_id = database.loadGeoObject(sql, dataset, 1, obj_list)
# 遍历加载的对象
for i in range(obj_list.size()):
geo = obj_list.at(i)
print(f"对象ID: {geo.getObjectId()}, 代码: {geo.getCode()}")
```
**动态分批加载**
```python
# 动态分批加载(适合大数据量场景)
def callback(obj_list, has_more):
"""回调函数,处理每批加载的对象"""
print(f"收到 {obj_list.size()} 个对象")
# 处理当前批次
for i in range(obj_list.size()):
geo = obj_list.at(i)
# 处理对象...
pass
# 返回 False 则停止加载,返回 True 则继续加载
return has_more
exist_ids = RowIdList() # 已加载对象的 RowId
database.dynBatchLoadObject(
rect, # 加载区域
dataset, # 数据集
exist_ids, # 已存在的对象 ID
callback, # 回调函数
1000.0, # 限制面积/长度(小于此值不加载)
False # 是否忽略细节级别
)
```
Sources: [PySSDatabase.py](PySSDatabase.py#L368-L465)
### 对象保存与删除
保存和删除操作支持单个对象、批量对象、SQL 条件删除等多种方式。
```python
# 保存单个对象
geo = create_new_geo_object() # 创建新对象
result = database.saveGeoObject(dataset, geo)
# 批量保存对象
obj_list = GeoBaseList()
obj_list.append(geo1)
obj_list.append(geo2)
result = database.saveGeoObject(dataset, obj_list)
# 删除单个对象(按 ID
result = database.deleteObject(1001, "RoadLayer")
# 按 SQL 删除
result = database.deleteObject("DELETE FROM RoadLayer WHERE status = 0")
# 按区域和类型删除
from sunvpy.PySSCore import DblRect, e_Line_Obj
rect = DblRect(116.3, 39.9, 116.4, 39.95)
result = database.deleteObject(rect, "RoadLayer", e_Line_Obj)
```
### 状态与时间管理
Database 接口提供了对象状态和时间戳的更新功能,这对于追踪对象变更历史非常重要。
```python
# 更新对象修改时间
import time
current_time = int(time.time())
database.resetDateTime(1001, current_time, "RoadLayer")
# 更新对象状态
database.resetStatus(1001, dataset)
# 批量更新状态和时间
geo_list = GeoBaseList()
# ... 加载对象到 geo_list ...
database.resetObjStatusAndDateTime("RoadLayer", geo_list)
```
Sources: [PySSDatabase.py](PySSDatabase.py#L482-L526)
## GeoEditMixin 高级编辑接口
GeoEditMixin 将数据库操作与对象编辑功能结合,提供了更高级的抽象,适合脚本化工作流程中的地理数据编辑场景。该接口通过对象缓存机制,实现了批量编辑和事务性保存。
### 对象创建与缓存流程
GeoEditMixin 使用缓存机制提高编辑效率,所有修改首先在内存中进行,最后统一保存到数据库。
```mermaid
flowchart TD
A[开始编辑] --> B[创建新对象<br/>createNewObjByCode]
B --> C[设置属性<br/>setNewObjValue]
C --> D[添加坐标点<br/>addNewObjPoint]
D --> E{操作类型}
E -->|添加到选择集| F[addNewObjToSelObjList<br/>仅显示,不保存]
E -->|添加到保存列表| G[addNewObjToSaveObjList<br/>准备保存]
F --> H[继续编辑其他对象]
G --> H
H --> I{是否完成编辑?}
I -->|否| B
I -->|是| J[saveBufferObjToDatabase<br/>批量保存]
J --> K[转换 MemoData<br/>transMemoDataToExtendAttr]
K --> L[添加到地图<br/>addGeoObject]
L --> M[保存到数据库<br/>saveDatabase]
M --> N[清理缓存<br/>clear lists]
N --> O[编辑完成]
```
**完整示例**
```python
from sunvpy.PySSCore import GeoBaseList
from sunvpy.PySSMath import Point3D
# 1. 通过编码创建新对象
obj, geo = ss_process.createNewObjByCode(150) # 道路编码
# 2. 设置基本属性
ss_process.setNewObjValue("SSObj_Name", "新建道路")
ss_process.setNewObjValue("SSObj_Code", "150")
ss_process.setNewObjValue("SSObj_Color", "255")
# 3. 设置扩展属性
ss_process.setNewObjValue("[road_type]", "主干道")
ss_process.setNewObjValue("[pavement]", "沥青")
ss_process.setNewObjValue("[width]", "12.5")
# 4. 添加坐标点
points = [(116.400, 39.900, 0.0),
(116.410, 39.905, 0.0),
(116.420, 39.910, 0.0)]
for pt in points:
ss_process.addNewObjPoint(
pt[0], pt[1], pt[2], # x, y, z
0, # 点类型
"" # 点名称
)
# 5. 添加到保存列表(准备保存到数据库)
ss_process.addNewObjToSaveObjList()
# 6. 创建另一个对象
obj2, geo2 = ss_process.createNewObjByClass("道路注记")
ss_process.setNewObjValue("SSObj_FontString", "主干道")
ss_process.addNewObjPoint(116.410, 39.905, 0.0, 0, "")
ss_process.addNewObjToSaveObjList()
# 7. 批量保存所有缓存对象到数据库
ss_process.saveBufferObjToDatabase()
print("所有对象已保存到数据库")
```
**关键方法说明**
| 方法 | 功能 | 缓存位置 |
|------|------|----------|
| `createNewObjByCode()` | 通过编码创建对象 | `curNewObj` |
| `createNewObjByClass()` | 通过注记类创建对象 | `curNewObj` |
| `setNewObjValue()` | 设置对象属性 | `curNewObj` |
| `addNewObjPoint()` | 添加坐标点 | `curNewObj` |
| `addNewObjToSelObjList()` | 添加到选择集 | `selGeoList` / `selNoteList` |
| `addNewObjToSaveObjList()` | 添加到保存列表 | `newBufferObjList` / `newBufferNoteList` |
| `saveBufferObjToDatabase()` | 批量保存到数据库 | 全部缓存 |
Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L100-L450)
### MemoData 与扩展属性转换
GeoEditMixin 提供了 MemoData备注数据与扩展属性之间的自动转换机制确保数据的一致性和完整性。
```python
# 将选择集对象的 MemoData 转换为扩展属性
sel_geo_list = GeoBaseList()
# ... 加载对象到 sel_geo_list ...
ss_process.transMemoDataToExtendAttr(sel_geo_list)
# 现在对象的 MemoData 已转换为标准扩展属性
# 在保存时会自动进行转换
ss_process.bufferObjList.append(geo_with_memodata)
ss_process.saveBufferObjToDatabase() # 自动调用转换
```
Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L430-L450)
### 删除缓存管理
GeoEditMixin 提供了删除对象的缓存机制,支持批量删除操作。
```python
# 标记要删除的对象
del_list = GeoBaseList()
del_list.append(geo1)
del_list.append(geo2)
# 添加到删除缓存
ss_process.delBufferGeoList.append(del_list)
# 在 saveBufferObjToDatabase() 时统一删除
ss_process.saveBufferObjToDatabase() # 会处理 delBufferGeoList
```
Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L450-L460)
## 数据结构容器
数据库更新接口使用了多个 SWIG 封装的数据容器类,这些容器提供了高效的集合操作和与 C++ 的无缝交互。
### StringArray 字符串数组
StringArray 是用于存储字符串序列的动态数组容器,广泛用于字段名列表、值列表等场景。
```python
from sunvpy.PySSDatabase import StringArray
fields = StringArray()
fields.append("code")
fields.append("name")
fields.append("value")
# 访问元素
first_field = fields[0] # "code"
# 迭代访问
for i in range(fields.size()):
print(fields[i])
# 查找元素
idx = -1
for i in range(fields.size()):
if fields[i] == "name":
idx = i
break
# 删除元素
if idx != -1:
fields.erase(idx)
# 清空数组
fields.clear()
```
Sources: [PySSDatabase.py](PySSDatabase.py#L100-L245)
### AttrList 属性列表
AttrList 是专门用于存储地物属性的键值对容器,提供了类似字典的访问接口。
```python
from sunvpy.PySSGisDBUpdate import AttrList
attrs = AttrList()
attrs["code"] = "150"
attrs["name"] = "道路"
attrs["width"] = "12.5"
# 访问属性
code = attrs["code"]
# 检查键是否存在
if "name" in attrs:
name = attrs["name"]
# 获取所有键
keys = attrs.keys()
for key in keys:
value = attrs[key]
print(f"{key}: {value}")
# 转换为 Python 字典
attrs_dict = attrs.asdict()
# 删除属性
if "width" in attrs:
del attrs["width"]
```
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L299-L398)
### FeatureList 地物列表
FeatureList 是专门用于存储地物对象的容器,支持批量地物操作。
```python
from sunvpy.PySSGisDBUpdate import FeatureList
from sunvpy.PySSCore import GeoBase
features = FeatureList()
features.append(geo1)
features.append(geo2)
# 访问地物
first_feature = features[0]
# 批量操作
for i in range(features.size()):
geo = features[i]
geo.setCode(200) # 修改编码
# 删除地物
if features.size() > 0:
features.pop_back() # 删除最后一个
# 清空列表
features.clear()
```
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L401-L493)
## 完整工作流示例
以下示例展示了如何使用数据库更新接口完成一个完整的数据同步和更新流程。
```python
from sunvpy.PySSGisDBUpdate import SSDbScript
from sunvpy.PySSCore import GeoBaseList, Point3D
from sunvpy.PySSDatabase import StringArray
def sync_and_update_road_data():
"""完整的道路数据同步和更新流程"""
# 1. 初始化和连接
db_script = SSDbScript()
if not db_script.login("admin", "password"):
print("登录失败")
return False
if not db_script.connectToTablespace("MainWorkspace"):
print("连接工作空间失败")
return False
# 2. 下载服务器数据到本地
region_coords = [(116.3, 39.9), (116.5, 39.9),
(116.5, 40.0), (116.3, 40.0)]
download_ok = db_script.downloadDBToLocalDB(
workspace_handle,
region_coords,
"RoadLayer",
"status = 1",
False
)
if not download_ok:
print(f"下载失败: {db_script.m_strLogInfos}")
return False
# 3. 在本地进行数据编辑
# ... 使用 GeoEditMixin 或直接使用 Database 接口编辑数据 ...
# 4. 查询需要更新的对象
fields = StringArray()
values = StringArray()
fields.append("code")
values.append("150")
results = db_script.searchFeatureAttr(
workspace_handle,
"RoadLayer",
"status = 1",
"code", # 排序字段
fields # 查询字段
)
# 5. 批量更新属性
update_fields = StringArray()
update_values = StringArray()
update_fields.append("status")
update_values.append("2")
db_script.editSDEDBTableRecord(
workspace_handle,
"RoadLayer",
"code IN (150, 151, 152)",
update_fields,
update_values
)
# 6. 上传本地修改到服务器
upload_ok = db_script.uploadLocalDBToDB(
workspace_handle,
"RoadLayer",
2 # 新增+更新模式
)
if not upload_ok:
print(f"上传失败: {db_script.m_strLogInfos}")
return False
# 7. 创建备份
backup_ok = db_script.backupDataToEgdb(
workspace_handle,
f"D:/Backup/road_backup_{time.strftime('%Y%m%d')}.egdb"
)
# 8. 登出
db_script.logout()
print("数据同步和更新完成")
return True
# 执行流程
if __name__ == "__main__":
sync_and_update_road_data()
```
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L1-L493), [PySSDatabase.py](PySSDatabase.py#L1-L1643)
## 错误处理与日志
数据库更新接口提供了完善的错误处理和日志记录机制,帮助开发者诊断和解决问题。
### 日志信息获取
SSDbScript 类提供了 `m_strLogInfos` 属性用于获取操作日志信息。
```python
db_script = SSDbScript()
# 执行操作
result = db_script.uploadLocalDBToDB(workspace_handle, "RoadLayer", 2)
# 检查结果并获取日志
if not result:
log_info = db_script.m_strLogInfos
print(f"操作失败: {log_info}")
# 可以将日志写入文件
with open("db_error.log", "a", encoding="utf-8") as f:
f.write(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {log_info}\n")
# 也可以使用 outputMsgInfo 输出信息
db_script.outputMsgInfo("操作开始...")
db_script.outputMsgInfo("操作完成")
```
### 常见错误处理
```python
try:
# 连接错误处理
if not db_script.login("user", "pass"):
raise ConnectionError("数据库连接失败")
# 权限错误处理
result = db_script.uploadLocalDBToDB(workspace_handle, "ProtectedLayer", 2)
if not result and "permission" in db_script.m_strLogInfos.lower():
raise PermissionError("没有权限执行此操作")
# 数据验证错误
result = db_script.addSDEDBTableRecord(
workspace_handle, "MyTable", fields, values
)
if not result and "constraint" in db_script.m_strLogInfos.lower():
raise ValueError("数据违反约束条件")
except ConnectionError as e:
print(f"连接错误: {e}")
db_script.logout()
except PermissionError as e:
print(f"权限错误: {e}")
# 提示用户联系管理员
except ValueError as e:
print(f"数据错误: {e}")
# 记录错误数据
except Exception as e:
print(f"未知错误: {e}")
print(f"日志信息: {db_script.m_strLogInfos}")
```
Sources: [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L76-L78), [PySSGisDBUpdate.py](PySSGisDBUpdate.py#L283-L284)
## 性能优化建议
在使用数据库更新接口时,遵循以下性能优化建议可以显著提升操作效率:
### 批量操作优先
```python
# 不推荐:逐个保存对象
for obj in large_object_list:
database.saveGeoObject(dataset, obj) # 每次都提交事务
# 推荐:批量保存
obj_list = GeoBaseList()
for obj in large_object_list:
obj_list.append(obj)
database.saveGeoObject(dataset, obj_list) # 一次性保存
```
### 合理使用事务
```python
# 批量操作使用事务
database.beginTransaction()
try:
for i in range(1000):
database.execute(f"UPDATE Table SET value = {i}")
database.commitTransaction()
except:
database.rollbackTransaction()
```
### 使用增量下载
```python
# 首次全量下载
db_script.downloadDBToLocalDB1(workspace_handle, region_guid, False)
# 后续增量下载(只下载变更数据)
db_script.downloadDBToLocalDB1(workspace_handle, region_guid, True)
```
### 限制查询范围
```python
# 不推荐:查询整个表
result = db_script.searchFeatureAttr(tablespace, "Layer", "", "", fields)
# 推荐:限制查询条件
result = db_script.searchFeatureAttr(
tablespace,
"Layer",
"status = 1 AND code > 100", # 添加过滤条件
"code",
fields
)
```
### 使用对象缓存
```python
# 使用 GeoEditMixin 的缓存机制
for i in range(100):
obj, geo = ss_process.createNewObjByCode(code)
ss_process.setNewObjValue("name", f"对象{i}")
ss_process.addNewObjPoint(x, y, z, 0, "")
ss_process.addNewObjToSaveObjList()
# 一次性保存所有对象
ss_process.saveBufferObjToDatabase()
```
Sources: [PySSDatabase.py](PySSDatabase.py#L332-L348), [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L430-L460)
## 相关接口与扩展
数据库更新接口与其他 SunvStation 组件紧密集成,形成了完整的 GIS 数据管理生态系统。
### 与数据交换的集成
数据库更新接口与数据交换接口配合使用,可以实现数据的导入导出和格式转换。
```python
from sunvpy.PySSDataX import DataXScript
# 配置数据交换参数
data_x = DataXScript()
data_x.setDataXParameter("ImportFormat", "SHP")
data_x.setDataXParameter("ImportPath", "D:/Data/roads.shp")
# 执行数据导入
data_x.importData()
# 使用数据库更新接口处理导入的数据
# ... 执行更新操作 ...
# 配置数据导出
data_x.clearDataXParameter()
data_x.setDataXParameter("ExportFormat", "GDB")
data_x.setDataXParameter("ExportPath", "D:/Data/output.gdb")
# 执行数据导出
data_x.exportData()
```
更多数据交换详情请参考 [数据交换参数配置](26-shu-ju-jiao-huan-can-shu-pei-zhi)。
### 与地理对象编辑的集成
数据库更新接口与地理对象编辑功能深度集成,支持从对象创建到数据库保存的完整流程。
```python
# 创建对象(使用 GeoEditMixin
obj, geo = ss_process.createNewObjByCode(150)
ss_process.setNewObjValue("name", "测试道路")
ss_process.addNewObjPoint(x1, y1, z1, 0, "")
ss_process.addNewObjPoint(x2, y2, z2, 0, "")
ss_process.addNewObjPoint(x3, y3, z3, 0, "")
# 添加到保存列表
ss_process.addNewObjToSaveObjList()
# 使用 Database 接口进行高级操作
database.beginTransaction()
ss_process.saveBufferObjToDatabase()
database.commitTransaction()
```
更多地理对象编辑详情请参考 [创建默认地物对象](19-chuang-jian-mo-ren-di-wu-dui-xiang) 和 [批量保存到数据库](24-pi-liang-bao-cun-dao-shu-ju-ku)。
Sources: [PySSDataX.py](PySSDataX.py#L100-L173), [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L100-L460)
## 下一步学习
掌握数据库更新接口后,建议继续学习以下相关主题,以构建完整的 SunvStation 开发知识体系:
- **[批量保存到数据库](24-pi-liang-bao-cun-dao-shu-ju-ku)**:深入了解对象缓存机制和批量保存策略
- **[数据交换参数配置](26-shu-ju-jiao-huan-can-shu-pei-zhi)**:学习如何配置和执行数据导入导出操作
- **[创建默认地物对象](19-chuang-jian-mo-ren-di-wu-dui-xiang)**:掌握对象创建和属性设置的完整流程
- **[SSProcessManager 完整 API](40-ssprocessmanager-wan-zheng-api)**:查看完整的 API 参考文档
- **[错误处理与异常管理](39-cuo-wu-chu-li-yu-yi-chang-guan-li)**:学习系统级的错误处理和日志管理