主键、自增与必填约束

单一主键

#[derive(Debug, Clone, EntityType)]
#[table("users")]
pub struct User {
    #[primary_key]
    #[auto_increment]
    pub user_id: i32,

    #[required]
    pub email: String,
}

复合主键

`rust-ef` 支持复合主键,但需在 `entity_meta()` 中正确声明多列。当前 derive 宏对复合主键的自动化支持有限,复杂场景建议手动实现 `IGetKeyValues`。

impl IGetKeyValues for OrderLine {
    fn key_values(&self) -> HashMap<String, DbValue> {
        let mut m = HashMap::new();
        m.insert("order_id".into(), DbValue::I32(self.order_id));
        m.insert("line_no".into(), DbValue::I32(self.line_no));
        m
    }
}

自增回填

INSERT 后,`save_changes()` 会自动通过 `RETURNING` 语句回填自增主键值:

ctx.add::<Blog>(Blog { blog_id: 0, .. });
ctx.save_changes().await?;
// blog_id 现在包含数据库生成的实际值

必填约束

| 类型 | 默认可空性 | 加 `#[required]` 后 | |------|-----------|-------------------| | `String` | 可空 | `NOT NULL` | | `i32` / `f64` | 非空(值类型) | 无变化 | | `Option<T>` | 可空 | 冲突,不建议同时使用 |

设计要点

| 实践 | 说明 | |------|------| | 自增主键用 `i32` | `i64` 也支持,但 `i32` 在大多数场景足够且回填路径最成熟 | | `Option<String>` 不加 `#[required]` | 否则语义冲突 |

下一节:[索引、唯一性与并发标记](indexes-concurrency.md)