ChangeTracker 与 DetectChanges
`ChangeTracker` 负责对比实体的当前值与原始快照,自动标记 `Modified` 状态。
自动 DetectChanges
`save_changes()` 内部会自动调用 `detect_changes()`:
ctx.attach::<Blog>(blog); // 记录快照
blog.rating = 99; // 修改属性
// save_changes 内部自动 detect_changes,发现差异后生成 UPDATE
ctx.save_changes().await?;
手动 DetectChanges
当你需要在 SaveChanges 之前了解哪些实体发生了变化:
ctx.detect_changes();
let modified = ctx.set::<Blog>().modified_entities();
for blog in modified {
println!("Will update: {}", blog.url);
}
快照机制
`attach()` 时,`DbContext` 会调用 `entity.snapshot()` 保存一份 `EntitySnapshot`。`detect_changes()` 对比当前 `snapshot()` 与原始值,若不同则标记为 `Modified`。
设计要点
| 实践 | 说明 | |------|------| | 显式 `update()` 可跳过 DetectChanges | 如果你确定实体已修改,直接 `update()` 更高效 | | 大量实体 Attach 后慎用 DetectChanges | 快照对比有 O(n) 开销 |
与 EFCore 的差异(已知限制)
rust-ef 当前的 `ChangeTracker` 为**手动快照式**跟踪,与 EFCore 的代理式自动跟踪有以下差异:
| 维度 | EFCore | rust-ef | |---|---|---| | 查询自动跟踪 | 是 | 否,需显式 `attach()` | | 属性变更检测 | 自动(代理)| 手动 `detect_changes()` | | Identity Map | 是 | 否 | | 导航 Fixup | 自动 | 无 |
**当前推荐工作流**:查询后显式 `attach()` → 修改属性 → 调用 `update()` 标记 → `save_changes()`。或直接 `update(entity)` 跳过快照比对。
此项架构性差距将在 v0.5+ 评估代理式跟踪方案(可能需 nightly 特性或显著重写)。
下一章:[批量操作](../08-bulk-operations/INDEX.md)