数据检查记录的添加与加载是 SunvStation 数据质量保证系统中最为核心的两个操作。添加操作用于在数据验证过程中实时记录发现的问题，加载操作则用于恢复历史检查结果或在不同检查会话之间共享数据。这两个操作共同构成了检查记录管理的基础，支撑着完整的数据质量控制生命周期。

通过精心设计的参数体系和灵活的持久化机制，添加与加载操作能够适应从快速原型验证到大规模生产检查的各种应用场景。掌握这两个操作的使用方法，是编写高质量数据检查脚本的关键技能。

Sources: [PySSCheck.py](PySSCheck.py#L101-L160)

## 添加检查记录详解

添加检查记录是数据验证脚本中最为频繁的操作，通过 `AddCheckRecord()` 方法将发现的数据问题记录到内存中的检查记录集合中。该方法通过丰富的参数体系完整地描述了检查发现的问题，包括问题分类、空间位置、关联对象等多维度信息。

### 方法签名与参数说明

`AddCheckRecord()` 方法的完整签名包含10个参数，每个参数都有其特定的语义和使用场景：

```python
def AddCheckRecord(self, group, check, checkmodel, description, x, y, z, objtype, geoids, noteids):
```

| 参数名 | 数据类型 | 必需 | 说明 | 典型值 |
|--------|---------|------|------|--------|
| `group` | string | 是 | 检查组名称，用于逻辑分组 | "拓扑检查"、"属性完整性" |
| `check` | string | 是 | 检查项名称，标识具体检查类型 | "重叠检查"、"必填项缺失" |
| `checkmodel` | int | 是 | 检查模式标识符 | 0-255之间的整数值 |
| `description` | string | 是 | 问题描述或错误详情 | 简洁清晰的问题描述文本 |
| `x` | float | 是 | 问题位置X坐标 | 地理坐标系统中的X值 |
| `y` | float | 是 | 问题位置Y坐标 | 地理坐标系统中的Y值 |
| `z` | float | 是 | 问题位置Z坐标 | 高程值，通常为0.0 |
| `objtype` | int | 是 | 关联对象的类型 | 1=点，2=线，3=面等 |
| `geoids` | string | 是 | 地物对象ID列表，逗号分隔 | "1001,1002,1003" |
| `noteids` | string | 是 | 注记对象ID列表，逗号分隔 | "2001,2002" |

该设计遵循**信息完整性原则**，确保每条记录包含问题追踪和定位所需的所有信息，同时通过字符串形式的ID列表支持多对象关联场景。

Sources: [PySSCheck.py](PySSCheck.py#L113-L114)

### 添加操作的工作流程

理解添加操作的内部处理流程有助于编写更高效的检查脚本。当调用 `AddCheckRecord()` 时，系统会执行一系列验证和处理步骤：

```mermaid
flowchart TD
    A[调用 AddCheckRecord] --> B{参数有效性验证}
    B -->|通过| C[创建检查记录对象]
    B -->|失败| D[记录添加失败]
    
    C --> E[设置 group 和 check 字段]
    E --> F[设置空间坐标 x, y, z]
    F --> G[设置 objtype 对象类型]
    G --> H[解析 geoids 字符串为ID列表]
    H --> I[解析 noteids 字符串为ID列表]
    I --> J[设置 description 描述信息]
    J --> K[记录添加到内存集合]
    K --> L[返回成功状态]
    
    D --> M[抛出异常或返回错误]
    
    style C fill:#e1f5ff
    style K fill:#fff4e1
    style L fill:#d4edda
```

该流程体现了**防御性编程**的设计思想，在添加记录前进行参数验证，避免无效数据污染检查记录集合。坐标和对象类型信息的设置支持后续的空间查询和类型过滤，而ID列表的解析则实现了从字符串表示到结构化数据的转换。

Sources: [PySSCheck.py](PySSCheck.py#L113-L114)

### 基础添加示例

以下是一个完整的添加检查记录示例，展示了如何在实际脚本中记录拓扑重叠问题：

```python
from sunvpy.PySSCheck import CheckFunForPY
from sunvpy import SSProcess

# 创建检查记录管理实例
check_fun = CheckFunForPY()

# 设置选择条件，查找可能存在重叠的建筑物
SSProcess.clearSelection()
SSProcess.clearSelectCondition()
SSProcess.setSelectCondition("SSObj_LayerName", "==", "建筑")
SSProcess.setSelectCondition("SSObj_Type", "==", "3")  # 面对象
SSProcess.selectFilter()

# 遍历选择集，假设已通过某种算法检测到重叠
count = SSProcess.getSelGeoCount()
for i in range(count):
    geo_id = SSProcess.getSelGeoValue(i, "SSObj_ID")
    obj_type = int(SSProcess.getSelGeoValue(i, "SSObj_Type"))
    
    # 获取对象的空间位置（以第一个点为例）
    point_count = int(SSProcess.getSelGeoValue(i, "SSObj_PointCount"))
    if point_count > 0:
        x = float(SSProcess.getSelGeoValue(i, "SSObj_X"))
        y = float(SSProcess.getSelGeoValue(i, "SSObj_Y"))
        z = 0.0
        
        # 添加检查记录
        check_fun.AddCheckRecord(
            group="拓扑检查",
            check="重叠检查",
            checkmodel=1,  # 检查模式1表示重叠
            description=f"建筑物 {geo_id} 存在空间重叠",
            x=x, y=y, z=z,
            objtype=obj_type,
            geoids=str(geo_id),
            noteids=""
        )

# 输出统计信息
print(f"检查完成，共记录 {check_fun.GetCheckRecordCount()} 个重叠问题")
```

该示例展示了**选择集遍历与检查记录添加**的典型协作模式，这是数据检查脚本中最常见的使用场景。在实际应用中，重叠检测算法通常需要结合空间索引和几何运算库来实现。

Sources: [PySSCheck.py](PySSCheck.py#L113-L114)

### 多对象关联添加

许多数据质量问题涉及多个对象的相互作用，此时需要将多个对象ID记录到同一条检查记录中：

```python
# 假设检测到两个建筑物重叠
obj1_id = "1001"
obj2_id = "1002"
obj1_type = 3  # 面对象
obj2_type = 3

# 计算重叠区域的中心点
overlap_center_x = 123456.78
overlap_center_y = 345678.90
overlap_center_z = 0.0

# 添加包含多个对象ID的检查记录
check_fun.AddCheckRecord(
    group="拓扑检查",
    check="重叠检查",
    checkmodel=1,
    description=f"建筑物 {obj1_id} 与 {obj2_id} 存在空间重叠",
    x=overlap_center_x,
    y=overlap_center_y,
    z=overlap_center_z,
    objtype=obj1_type,  # 记录主对象的类型
    geoids=f"{obj1_id},{obj2_id}",  # 逗号分隔的多个ID
    noteids=""
)

print(f"已记录重叠问题，关联对象: {obj1_id}, {obj2_id}")
```

通过逗号分隔的字符串形式传递多个对象ID，既保持了接口的简洁性，又支持了复杂的多对象关系记录。在查询和分析时，可以按照逗号分隔符解析出各个对象ID，进行批量处理或关联分析。

Sources: [PySSCheck.py](PySSCheck.py#L113-L114)

## 加载检查记录详解

加载检查记录是通过 `LoadCheckRecord()` 方法将持久化的检查记录文件读取到内存中，用于历史数据恢复、对比分析或跨会话数据共享。该方法是检查记录持久化机制的关键组成部分，为数据质量管理提供了时间维度的支持。

### 方法功能与返回值

`LoadCheckRecord()` 方法的签名非常简洁，没有显式参数：

```python
def LoadCheckRecord(self):
```

该方法会从系统配置的默认位置加载检查记录文件，通常是在最后一次 `SaveCheckRecord()` 调用时保存的文件。方法返回一个布尔值，指示加载操作是否成功：

- **True**：加载成功，检查记录已恢复到内存中
- **False**：加载失败，可能是文件不存在、格式错误或权限问题

这种设计遵循**最小接口原则**，通过约定优于配置的方式简化了调用方的代码，同时通过返回值提供了必要的错误处理能力。

Sources: [PySSCheck.py](PySSCheck.py#L108-L109)

### 加载操作的执行过程

理解加载操作的内部流程有助于排查问题并优化使用方式：

```mermaid
sequenceDiagram
    participant Script as 检查脚本
    participant CF as CheckFunForPY
    participant File as 持久化文件
    participant Memory as 内存记录集合
    
    Script->>CF: LoadCheckRecord()
    CF->>CF: 获取默认文件路径
    CF->>File: 打开检查记录文件
    alt 文件存在且可读
        File->>CF: 返回文件句柄
        CF->>CF: 解析文件格式
        CF->>CF: 清空当前内存集合
        loop 遍历文件中的记录
            CF->>Memory: 添加记录到集合
        end
        CF->>Script: 返回 True
    else 文件不存在或格式错误
        CF->>Script: 返回 False
    end
```

该流程体现了**原子性替换**的设计思想：加载操作会清空当前内存中的检查记录集合，然后用文件中的记录完全替换。这意味着加载操作是一个破坏性操作，如果需要保留当前记录，应该在加载前进行备份或另存。

Sources: [PySSCheck.py](PySSCheck.py#L108-L109)

### 基础加载示例

以下是一个完整的加载检查记录示例：

```python
from sunvpy.PySSCheck import CheckFunForPY

# 创建检查记录管理实例
check_fun = CheckFunForPY()

# 加载历史检查记录
success = check_fun.LoadCheckRecord()

if success:
    record_count = check_fun.GetCheckRecordCount()
    print(f"成功加载 {record_count} 条历史检查记录")
    
    # 遍历并显示前5条记录
    for i in range(min(5, record_count)):
        fields = "group,check,description"
        values = ""
        check_fun.GetCheckRecordValue(i, fields, values)
        print(f"  记录 {i}: {values}")
else:
    print("加载失败，可能文件不存在或格式错误")
```

该示例展示了加载操作的标准流程：调用方法、检查返回值、获取记录数量、遍历记录内容。在批量处理场景中，通常会在加载后进行统计分析或与其他数据源进行对比。

Sources: [PySSCheck.py](PySSCheck.py#L108-L109)

### 加载前的清空处理

由于 `LoadCheckRecord()` 会自动清空当前内存中的检查记录集合，在某些场景下可能需要先保存当前记录：

```python
from sunvpy.PySSCheck import CheckFunForPY
import datetime

check_fun = CheckFunForPY()

# 假设当前已有一些检查记录
current_count = check_fun.GetCheckRecordCount()
print(f"当前内存中有 {current_count} 条检查记录")

if current_count > 0:
    # 生成带时间戳的备份文件名
    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    backup_filename = f"check_backup_{timestamp}.tmp"
    print(f"将当前记录备份到: {backup_filename}")
    
    # 保存当前记录（SaveCheckRecord会使用系统默认路径）
    check_fun.SaveCheckRecord()

# 现在加载历史记录
print("正在加载历史检查记录...")
success = check_fun.LoadCheckRecord()

if success:
    loaded_count = check_fun.GetCheckRecordCount()
    print(f"成功加载 {loaded_count} 条历史检查记录")
```

这种**备份-加载**模式在需要保留多个检查会话结果的场景中非常有用，例如在进行迭代式数据修复时，可以对比不同修复阶段的结果。

Sources: [PySSCheck.py](PySSCheck.py#L108-L112)

## 实践案例：质量追踪系统

在实际的数据生产项目中，添加与加载操作通常被整合到完整的数据质量追踪系统中。以下是一个综合示例，展示了如何构建一个简单的质量追踪解决方案。

### 场景说明

假设我们需要建立一个数据质量追踪系统，定期执行检查任务并记录结果，用于评估数据质量的改进趋势。系统需要支持以下功能：

1. 执行数据检查并记录问题
2. 加载历史记录进行对比
3. 生成质量报告

### 完整实现代码

```python
from sunvpy.PySSCheck import CheckFunForPY
from sunvpy import SSProcess
import datetime

class QualityTracker:
    """数据质量追踪器"""
    
    def __init__(self):
        self.check_fun = CheckFunForPY()
        self.check_results = []
    
    def run_check(self, check_name, check_func):
        """执行指定的检查任务"""
        print(f"\n开始执行检查: {check_name}")
        
        # 清空当前检查记录
        self.check_fun.ClearCheckRecord()
        
        # 执行检查函数
        issue_count = check_func(self.check_fun)
        
        # 记录检查结果
        result = {
            'name': check_name,
            'timestamp': datetime.datetime.now(),
            'count': issue_count,
            'saved': False
        }
        self.check_results.append(result)
        
        print(f"检查完成，发现 {issue_count} 个问题")
        return issue_count
    
    def load_previous_results(self):
        """加载上次的检查结果"""
        print("\n正在加载历史检查结果...")
        success = self.check_fun.LoadCheckRecord()
        
        if success:
            prev_count = self.check_fun.GetCheckRecordCount()
            print(f"成功加载 {prev_count} 条历史记录")
            return prev_count
        else:
            print("未找到历史记录，将创建新的基准")
            return 0
    
    def save_results(self):
        """保存当前检查结果"""
        if self.check_results:
            self.check_fun.SaveCheckRecord()
            self.check_results[-1]['saved'] = True
            print("\n检查结果已保存")
    
    def generate_report(self):
        """生成质量报告"""
        print("\n" + "="*60)
        print("数据质量检查报告")
        print("="*60)
        
        prev_count = self.load_previous_results()
        
        # 执行各项检查
        self.run_check("拓扑重叠检查", self.check_overlap)
        self.run_check("属性完整性检查", self.check_attributes)
        
        # 保存结果
        self.save_results()
        
        # 输出对比报告
        curr_count = self.check_fun.GetCheckRecordCount()
        print(f"\n质量改进情况:")
        print(f"  上次检查问题数: {prev_count}")
        print(f"  本次检查问题数: {curr_count}")
        print(f"  改进/新增: {prev_count - curr_count}")
        print("="*60)
    
    def check_overlap(self, check_fun):
        """拓扑重叠检查"""
        # 实际应用中这里应有具体的重叠检测算法
        # 以下为模拟代码
        
        SSProcess.clearSelection()
        SSProcess.clearSelectCondition()
        SSProcess.setSelectCondition("SSObj_Type", "==", "3")  # 面对象
        SSProcess.selectFilter()
        
        count = SSProcess.getSelGeoCount()
        issue_count = 0
        
        for i in range(count):
            geo_id = SSProcess.getSelGeoValue(i, "SSObj_ID")
            obj_type = int(SSProcess.getSelGeoValue(i, "SSObj_Type"))
            
            # 模拟重叠检测：假设每10个对象有1个重叠
            if i % 10 == 0:
                x = float(SSProcess.getSelGeoValue(i, "SSObj_X"))
                y = float(SSProcess.getSelGeoValue(i, "SSObj_Y"))
                
                check_fun.AddCheckRecord(
                    group="拓扑检查",
                    check="重叠检查",
                    checkmodel=1,
                    description=f"面对象 {geo_id} 存在重叠",
                    x=x, y=y, z=0.0,
                    objtype=obj_type,
                    geoids=str(geo_id),
                    noteids=""
                )
                issue_count += 1
        
        return issue_count
    
    def check_attributes(self, check_fun):
        """属性完整性检查"""
        SSProcess.clearSelection()
        SSProcess.clearSelectCondition()
        SSProcess.setSelectCondition("SSObj_Name", "==", "")
        SSProcess.selectFilter()
        
        count = SSProcess.getSelGeoCount()
        issue_count = 0
        
        for i in range(count):
            geo_id = SSProcess.getSelGeoValue(i, "SSObj_ID")
            obj_type = int(SSProcess.getSelGeoValue(i, "SSObj_Type"))
            
            x = float(SSProcess.getSelGeoValue(i, "SSObj_X"))
            y = float(SSProcess.getSelGeoValue(i, "SSObj_Y"))
            
            check_fun.AddCheckRecord(
                group="属性检查",
                check="名称缺失",
                checkmodel=2,
                description=f"对象 {geo_id} 缺少名称属性",
                x=x, y=y, z=0.0,
                objtype=obj_type,
                geoids=str(geo_id),
                noteids=""
            )
            issue_count += 1
        
        return issue_count

# 使用质量追踪器
if __name__ == "__main__":
    tracker = QualityTracker()
    tracker.generate_report()
```

该示例展示了**面向对象**的检查记录管理模式，通过封装检查逻辑和记录管理，构建了一个可复用的质量追踪系统。系统利用加载操作获取历史基准，通过添加操作累积检查结果，最后通过保存操作持久化数据，形成完整的质量追踪闭环。

Sources: [PySSCheck.py](PySSCheck.py#L108-L125)

## 最佳实践与注意事项

在实际开发中，遵循最佳实践可以显著提升检查脚本的可靠性和性能。

### 参数传递的最佳实践

**使用常量定义检查组和检查项名称**，避免硬编码字符串：

```python
# 定义检查常量
CHECK_GROUPS = {
    'TOPOLOGY': '拓扑检查',
    'ATTRIBUTE': '属性检查',
    'GEOMETRY': '几何检查'
}

CHECK_ITEMS = {
    'OVERLAP': '重叠检查',
    'GAP': '间隙检查',
    'MISSING_NAME': '名称缺失',
    'INVALID_VALUE': '值非法'
}

# 使用常量
check_fun.AddCheckRecord(
    group=CHECK_GROUPS['TOPOLOGY'],
    check=CHECK_ITEMS['OVERLAP'],
    checkmodel=1,
    description="检测到重叠",
    x=x, y=y, z=0.0,
    objtype=obj_type,
    geoids=geo_id,
    noteids=""
)
```

这种做法提高了代码的可维护性，当需要修改检查名称时只需修改常量定义，而不需要查找并替换所有使用位置。

Sources: [PySSCheck.py](PySSCheck.py#L113-L114)

### 坐标信息的准确获取

添加检查记录时的坐标信息对问题定位至关重要，应确保坐标的准确性和一致性：

```python
def get_problem_center_point(process, geo_index):
    """获取问题对象的中心点坐标"""
    # 方法1：直接使用对象的X,Y属性
    x = float(process.getSelGeoValue(geo_index, "SSObj_X"))
    y = float(process.getSelGeoValue(geo_index, "SSObj_Y"))
    z = float(process.getSelGeoValue(geo_index, "SSObj_Z"))
    return x, y, z

def get_problem_focal_point(process, geo_index):
    """获取对象的几何中心（更精确）"""
    from sunvpy.PySSMath import getPolygonFocus
    
    # 获取对象的所有坐标点
    point_count = int(process.getSelGeoValue(geo_index, "SSObj_PointCount"))
    
    # 构建点列表
    points = []
    for i in range(point_count):
        # 这里需要根据实际API获取点坐标
        # 简化为使用对象中心
        pass
    
    # 计算几何中心
    center = getPolygonFocus(...)
    return center[0], center[1], 0.0
```

对于面对象，使用几何中心（Focal Point）比使用第一个顶点坐标更准确，能够更好地表示问题的空间位置。

Sources: [PySSCheck.py](PySSCheck.py#L113-L114)

### 加载操作的错误处理

加载操作可能因各种原因失败，应进行适当的错误处理：

```python
def safe_load_check_record(check_fun):
    """安全加载检查记录"""
    try:
        success = check_fun.LoadCheckRecord()
        if success:
            return check_fun.GetCheckRecordCount()
        else:
            print("警告: 加载失败，可能不存在历史记录")
            return 0
    except Exception as e:
        print(f"加载异常: {e}")
        return 0

# 使用示例
prev_count = safe_load_check_record(check_fun)
if prev_count > 0:
    print(f"成功加载 {prev_count} 条历史记录")
else:
    print("将建立新的检查基准")
```

通过try-except结构捕获可能的异常，并提供友好的错误提示，可以显著提升脚本的健壮性。

Sources: [PySSCheck.py](PySSCheck.py#L108-L109)

### 批量加载与增量更新

在大规模检查场景中，可以考虑增量加载策略：

```python
class IncrementalChecker:
    """增量式检查器"""
    
    def __init__(self, check_fun):
        self.check_fun = check_fun
        self.new_records = 0
        self.existing_records = 0
    
    def add_with_deduplication(self, group, check, checkmodel, description, x, y, z, objtype, geoids, noteids):
        """添加记录时去重"""
        # 检查是否已存在相似记录
        count = self.check_fun.GetCheckRecordCount()
        is_duplicate = False
        
        for i in range(count):
            fields = "group,check,geoids"
            values = ""
            self.check_fun.GetCheckRecordValue(i, fields, values)
            
            # 简单的去重逻辑：相同组、检查项和对象ID视为重复
            if values == f"{group},{check},{geoids}":
                is_duplicate = True
                break
        
        if is_duplicate:
            self.existing_records += 1
        else:
            self.check_fun.AddCheckRecord(group, check, checkmodel, description, x, y, z, objtype, geoids, noteids)
            self.new_records += 1
    
    def load_and_update(self):
        """加载历史记录并进行增量更新"""
        # 加载历史记录
        self.check_fun.LoadCheckRecord()
        base_count = self.check_fun.GetCheckRecordCount()
        
        print(f"加载历史记录: {base_count} 条")
        
        # 执行增量检查（调用 add_with_deduplication 而不是直接调用 AddCheckRecord）
        # ... 检查逻辑 ...
        
        print(f"新增记录: {self.new_records} 条")
        print(f"重复记录: {self.existing_records} 条")
        print(f"总计记录: {self.check_fun.GetCheckRecordCount()} 条")
```

这种**增量式**的检查策略在长期运行的数据质量监控系统中非常有用，可以避免重复记录相同的问题，同时保持检查结果的时效性。

Sources: [PySSCheck.py](PySSCheck.py#L108-L125)

## 进阶主题：与系统集成

添加与加载检查记录不仅可以在独立脚本中使用，还可以与 SunvStation 系统的其他功能深度集成。

### 与地图显示的集成

检查记录的空间信息可以用于在地图上高亮显示问题位置：

```python
from sunvpy.PySSCheck import CheckFunForPY
from sunvpy import SSProcess

def highlight_check_results(check_fun):
    """在地图上高亮显示检查结果"""
    count = check_fun.GetCheckRecordCount()
    
    # 清除当前选择集
    SSProcess.clearSelection()
    
    for i in range(count):
        # 获取记录的坐标信息
        fields = "x,y,description,geoids"
        values = ""
        check_fun.GetCheckRecordValue(i, fields, values)
        
        # 解析坐标和描述
        parts = values.split(',')
        x = float(parts[0])
        y = float(parts[1])
        description = parts[2]
        geo_ids = parts[3]
        
        # 根据geo_ids选择并高亮对象
        for geo_id in geo_ids.split(','):
            SSProcess.clearSelectCondition()
            SSProcess.setSelectCondition("SSObj_ID", "==", geo_id)
            SSProcess.selectFilter()
            
            # 可以设置特定的显示样式
            # （具体实现取决于PySSView提供的功能）
        
    # 缩放到问题区域
    SSProcess.zoomToSelection()

# 使用示例
check_fun = CheckFunForPY()
check_fun.LoadCheckRecord()
highlight_check_results(check_fun)
```

通过将检查记录的空间坐标与地图显示功能结合，可以实现可视化的质量检查结果展示，便于用户快速定位和修复问题。

Sources: [PySSCheck.py](PySSCheck.py#L108-L125)

## 学习路径建议

掌握添加与加载检查记录是构建复杂数据检查系统的基础。建议按照以下路径深入学习：

1. **基础阶段**：首先阅读[数据检查记录管理](30-shu-ju-jian-cha-ji-lu-guan-li)，理解检查记录的整体架构和数据结构
2. **实践阶段**：在[显示检查结果](32-xian-shi-jian-cha-jie-guo)中学习如何可视化和分析检查结果
3. **进阶阶段**：通过[自定义检查规则](33-zi-ding-yi-jian-cha-gui-ze)学习构建完整的自定义检查解决方案

循序渐进的学习路径可以帮助您系统地掌握数据检查的各个组成部分，最终能够独立开发高质量的数据检查脚本。