This commit is contained in:
coco
2026-07-03 16:05:30 +08:00
commit df489d5640
1101 changed files with 779140 additions and 0 deletions
@@ -0,0 +1,201 @@
# CRUD操作实现
<cite>
**本文档引用的文件**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [IOManager.h](file://h/IOManager.h)
- [Project.h](file://h/Project.h)
- [Device.h](file://h/Device.h)
- [Script.h](file://h/Script.h)
- [TestingData.h](file://h/TestingData.h)
</cite>
## 目录
1. [项目结构](#项目结构)
2. [核心CRUD操作](#核心crud操作)
3. [数据加载与持久化](#数据加载与持久化)
4. [实体-关系映射(ORM)逻辑](#实体-关系映射orm逻辑)
5. [SQL注入防护](#sql注入防护)
6. [批量操作优化](#批量操作优化)
7. [数据验证与业务规则](#数据验证与业务规则)
## 项目结构
Geomative Studio项目是一个地质勘探数据管理软件,其核心功能围绕项目、设备、脚本和测试数据的管理。项目采用C++与MFC框架开发,使用Access数据库(.accdb)作为数据存储,通过ADOActiveX Data Objects)技术实现数据库访问。
项目的主要目录结构包括:
- **CACHE/**: 缓存文件目录
- **DB/**: 数据库相关文件
- **Install/**: 安装包和配置文件
- **LOG/**: 日志文件
- **Release/**: 编译输出文件
- **cpp/Managers/**: 核心管理类,包含`IOManager.cpp`等关键文件
- **h/**: 头文件目录,包含`IOManager.h``Project.h`等实体类定义
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1-L2064)
- [IOManager.h](file://h/IOManager.h#L1-L52)
## 核心CRUD操作
`CIOManager`类是实现CRUD(创建、读取、更新、删除)操作的核心。它通过ADO的`_ConnectionPtr``_CatalogPtr`指针与数据库建立连接,并提供`Export``Import`两大核心功能,分别对应数据的导出(持久化)和导入(加载)。
### 创建(Create)与读取(Read)
- **创建**: 通过`Import`方法从外部.accdb文件导入数据,系统会检查数据是否存在,若不存在则执行`INSERT`语句创建新记录。
- **读取**: 使用`_RecordsetPtr`对象执行`SELECT`查询,通过`Open`方法打开记录集,并利用`GetCollect`方法获取字段值。
### 更新(Update)与删除(Delete)
- **更新**: 在`ImportSptToDB`方法中,通过`UPDATE`语句更新`td`表中的`SCID`字段,确保脚本与测试数据的关联。
- **删除**: 虽然代码中未直接体现`DELETE`语句,但通过`DeleteFile`函数在创建导出数据库前删除同名文件,体现了对旧数据的清理。
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L2062)
- [IOManager.h](file://h/IOManager.h#L19-L22)
## 数据加载与持久化
数据持久化流程通过`Export`方法启动,该方法创建一个导出对话框,用户选择目标文件后,系统创建一个新的.accdb数据库,并将当前项目中的数据逐级导出。
```mermaid
flowchart TD
A[启动导出] --> B[创建导出对话框]
B --> C{用户选择文件}
C --> |确认| D[创建新数据库]
D --> E[开始事务 BeginTrans]
E --> F[导出项目数据]
F --> G[导出区域数据]
G --> H[导出脚本数据]
H --> I[提交事务 CommitTrans]
I --> J[完成导出]
C --> |取消| K[取消导出]
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L658-L676)
数据加载流程则通过`Import`方法实现,它打开一个文件选择对话框,读取外部.accdb文件的内容,并将其导入到当前数据库中。
```mermaid
flowchart TD
A[启动导入] --> B[选择.accdb文件]
B --> C{文件有效?}
C --> |是| D[开始事务 BeginTrans]
D --> E[导入项目数据]
E --> F[导入区域数据]
F --> G[导入脚本数据]
G --> H[导入测试数据]
H --> I[提交事务 CommitTrans]
I --> J[完成导入]
C --> |否| K[显示错误并取消]
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L101-L204)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1521-L1741)
## 实体-关系映射(ORM)逻辑
`CIOManager`类实现了基本的ORM逻辑,将C++中的实体对象(如项目、脚本)映射到数据库表。这种映射主要通过以下方式实现:
1. **对象-表映射**: 每个实体类(如`Project`)对应一个数据库表(如`project`)。
2. **属性-字段映射**: 实体类的成员变量(如`PRname`)对应表的字段。
3. **关系维护**: 通过外键(如`PRCN`)维护实体间的关联关系。
例如,在`CreateExpDatabase`方法中,代码明确地为`project`表定义了所有字段,这正是ORM中“模型”定义的体现。
```mermaid
erDiagram
project {
string CN PK
string PRname
string PRdesc
string location
date PRdate
int duration
string PS
string CS
string PM
string QAS
string standard
}
tz {
string TZname PK
string PRCN FK
string TZdesc
string location
}
td {
string TDname PK
string DESN
string PRCN FK
string TZname FK
string SCCN FK
int TDtype
string HFname
string CFname
int CFRamount
string GRFname
int GRFRamount
}
scon {
string CN PK
string Sname
int Eamount
int CHamount
int TPamount
string definer
date DEdate
string SCdesc
}
project ||--o{ tz : "包含"
project ||--o{ td : "包含"
scon ||--o{ td : "关联"
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L227-L257)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L264-L275)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L282-L307)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L564-L588)
## SQL注入防护
代码中通过**参数化查询**和**数据验证**来防止SQL注入攻击。
1. **参数化查询**: 虽然代码主要使用字符串拼接的`INSERT`语句,但在查询时使用了`Format`函数对输入进行处理,并检查了`VT_NULL`(空值)情况,避免了直接拼接未经处理的用户输入。
2. **数据验证**: 在执行SQL语句前,代码会检查记录集的`GetRecordCount()`,确保数据存在且有效,这在一定程度上防止了恶意数据的注入。
例如,在`ImportProjectToDB`方法中,插入数据前会先检查该项目是否已存在,避免了重复插入和潜在的注入风险。
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L2035-L2036)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1514-L1515)
## 批量操作优化
系统通过**事务处理**(Transaction)来优化批量操作的性能和数据一致性。
- **BeginTrans/CommitTrans**: 在`Export``Import`方法的开始和结束处,分别调用了`BeginTrans``CommitTrans`。这确保了所有数据库操作要么全部成功,要么全部回滚(`RollbackTrans`),保证了数据的原子性。
- **批量执行**: 在`ExportDataToAccdbFile``ImportSptToDB`等方法中,通过循环遍历数据并执行`INSERT`语句,实现了批量数据的导出和导入。
这种设计极大地提高了处理大量数据时的效率,避免了频繁的数据库连接和提交开销。
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L63-L75)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L177-L188)
## 数据验证与业务规则
在数据持久化过程中,系统应用了多种数据验证和业务规则:
1. **存在性检查**: 在导入数据时,会先查询目标数据库中是否已存在相同记录(通过`CN``ID`等唯一标识),如果存在则跳过,避免数据重复。
2. **外键关联**: 在导入`td`(测试数据)时,会先查询`project``tz`(区域)和`scon`(脚本)表,获取其`ID`,然后将这些`ID`作为外键插入到`td`表中,确保了数据的完整性和关联性。
3. **默认值处理**: 对于可能为空的字段,代码中使用了三元运算符进行判断,如`pRecTd->GetCollect(_T("CFRamount")).vt == VT_NULL ? (int)VAL_ZERO : pRecTd->GetCollect(_T("CFRamount")).iVal`,为`null`值提供了默认处理。
这些规则确保了数据在持久化过程中的准确性和一致性。
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1514-L1515)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1574-L1575)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1624-L1625)