Rust in Everything
基于 sea-orm 2.0.4

写入

读出来的是 Model,写进去的是 ActiveModel。ActiveModel 的每个字段是一个 ActiveValue:Set(要写)、Unchanged(读来的、没改)、NotSet(不写)。sea-orm 的写入都是从这三态出发,决定 INSERT 写哪几列、UPDATE 的 SET 有哪几项,再交给 sea-query 写成 SQL,经过和查询一样的 build → sqlx::query_with → acquire 发出去。相关源码:src/entity/active_value.rs 642 行、active_model.rs 2.6k(前一半是 ActiveModelTrait)、query/insert.rs 910、executor/insert.rs 610、query/update.rs + executor/update.rs 约 800、query/delete.rs + executor/delete.rs 约 540,大半是文档注释和测试。

  1. ActiveValue 与 ActiveModel:三态各自在 INSERT / UPDATE 里的意义;set_ne 只在新值等于 Unchanged 的旧值时保持不变,reset 把 Unchanged 变成 Set;into_active_model 得到全 Unchanged;from_json 按 JSON 里有没有这个键决定 Set 还是 NotSet。
  2. insert:Set 和 Unchanged 都会写进 INSERT;exec 只 RETURNING 主键,exec_with_returning 拿回整行;insert_many 里某一行没设的列被补成 NULL 而不是默认值;空列表在 2.0 里不发 SQL,1.1.20 会发 VALUES (DEFAULT);on_conflict 的 DO NOTHING 冲突时 exec 报 RecordNotInserted,TryInsert 给 Conflicted,但 exec_with_returning 给的是 RecordNotFound。
  3. update 与 delete:update 只 SET 被 Set 的非主键列,主键只进 WHERE;一列都没 Set 时不发 UPDATE,只按主键 SELECT 一次;没匹配到行报 None of the records are updated;主键 NotSet 在 2.0 是 PrimaryKeyNotSet,1.1.20 是 panic;update_many / delete_many 和 delete_by_id 的返回类型。
  4. save 与 ActiveModelBehavior:save 看主键有没有 NotSet 决定 insert 还是 update;四个钩子拿到什么,哪些写入路径不走钩子。
  5. 嵌套写入 ActiveModelEx:2.0 的 builder 一次写一棵关联对象,按外键依赖排顺序。
flowchart TB
  model[Model] -->|into_active_model| am["ActiveModel 全 Unchanged"]
  am -->|"Set / set_ne"| am2["ActiveModel 部分 Set"]
  am2 --> ins["Insert 写 Set 和 Unchanged"]
  am2 --> upd["UpdateOne 只 SET 被 Set 的列"]
  am2 --> del["DeleteOne 只用主键"]
  ins --> ret["RETURNING 拿回整行"]
  upd --> ret
  ret --> model

save 和钩子只是在上面这三条路前后各加一步,insert / update 的 SQL 由前三页讲清。语句怎么写成 $N 和参数在 QueryBuilder 与参数,DbErr 各分支的全貌在错误,写入要放进事务时看事务。

💬 关联讨论

发起讨论
加载中...