Ormer
Home
快速开始
GitHub
  • 简体中文
  • English
Home
快速开始
GitHub
  • 简体中文
  • English
  • Ormer 简介
  • 快速开始
  • 模型定义
  • 数据库连接
  • 数据操作
  • 查询构建器
  • 高级查询
  • 事务管理
  • 连接池

模型定义

模型是 Ormer 的核心,它定义了数据库表的结构和 Rust 类型之间的映射关系。

基本模型定义

使用 #[derive(Model)] 宏将 Rust 结构体定义为数据库模型:

use ormer::Model;

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary]
    id: i32,
    name: String,
    age: i32,
    email: String,
}

属性说明

  • #[table = "表名"] - 指定数据库表名
  • #[primary] - 标记主键字段
  • #[primary(auto)] - 标记自增主键
  • #[unique] - 唯一约束
  • #[index] - 创建索引

字段属性详解

1. 主键字段

普通主键

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary]
    id: i32,  // 需要手动指定值
    name: String,
}

自增主键

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: i32,  // 数据库自动生成
    name: String,
}

使用自增主键插入数据时:

// 方式1: 使用 Option<i32>
#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: Option<i32>,
    name: String,
}

db.insert(&User {
    id: None,  // 数据库自动生成
    name: "Alice".to_string(),
}).await?;

// 方式2: 使用 i32,手动指定
db.insert(&User {
    id: 1,  // 手动指定,但数据库会忽略
    name: "Alice".to_string(),
}).await?;

2. 唯一约束

单列唯一

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: i32,
    
    #[unique]
    email: String,  // 邮箱必须唯一
}

联合唯一约束

使用 group 参数创建联合唯一索引:

#[derive(Debug, Model)]
#[table = "user_roles"]
struct UserRole {
    #[primary(auto)]
    id: i32,
    
    #[unique(group = 1)]
    user_id: i32,
    
    #[unique(group = 1)]
    role_id: i32,
    // (user_id, role_id) 组合必须唯一
}

3. 索引

为经常查询的字段创建索引以提高性能:

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: i32,
    
    #[index]
    age: i32,  // 经常按年龄查询时添加索引
    
    #[index]
    created_at: String,
}

4. 可空字段

使用 Option<T> 表示可空字段:

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: i32,
    name: String,
    
    // 可选字段
    email: Option<String>,
    phone: Option<String>,
    age: Option<i32>,
}

插入数据时:

db.insert(&User {
    id: 1,
    name: "Alice".to_string(),
    email: Some("alice@example.com".to_string()),
    phone: None,  // 没有手机号
    age: Some(25),
}).await?;

支持的字段类型

基本类型

Rust 类型SQL 类型 (SQLite)SQL 类型 (PostgreSQL)SQL 类型 (MySQL)
i32INTEGERINTEGERINT
i64INTEGERBIGINTBIGINT
f64REALDOUBLEDOUBLE
StringTEXTTEXTTEXT
boolINTEGER (0/1)BOOLEANBOOLEAN

Option 类型

所有基本类型都可以包装在 Option 中:

Option<i32>
Option<i64>
Option<f64>
Option<String>
Option<bool>

完整示例

use ormer::Model;

#[derive(Debug, Model, Clone)]
#[table = "products"]
struct Product {
    #[primary(auto)]
    id: i32,
    
    #[unique]
    sku: String,  // 产品SKU,唯一
    
    name: String,
    price: f64,
    
    #[index]
    category_id: i32,  // 分类ID,添加索引
    
    #[index]
    stock: i32,  // 库存
    
    description: Option<String>,  // 可选描述
    is_active: bool,  // 是否上架
}

外键关系

虽然 Ormer 不强制使用外键约束,但你可以在模型中定义外键关系:

#[derive(Debug, Model)]
#[table = "posts"]
struct Post {
    #[primary(auto)]
    id: i32,
    
    #[foreign_key = "users(id)"]
    user_id: i32,  // 外键引用 users 表的 id
    
    title: String,
    content: String,
}

模型 Trait 方法

定义模型后,#[derive(Model)] 宏会自动实现以下方法:

query() / select()

创建查询构建器:

let query = User::query();
let select = User::select();

from_row()

从数据库行构建模型:

let user = User::from_row(&row)?;

field_values()

获取字段值列表 (用于 INSERT/UPDATE):

let values = user.field_values();

primary_key_column() / primary_key_value()

获取主键信息:

let pk_column = User::primary_key_column();  // "id"
let pk_value = user.primary_key_value();     // 实际值

创建表

使用 create_table 方法创建表:

db.create_table::<User>().await?;

这会生成类似如下的 SQL:

CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT,
    age INTEGER,
    email TEXT UNIQUE
)

注意:create_table 方法只负责创建表,不会验证表结构。如果表已存在,可能会报错。

验证表结构

使用 validate_table 方法验证表结构是否与模型定义匹配:

// 验证表结构
db.validate_table::<User>().await?;

该方法会检查:

  • 表是否存在
  • 列数量是否匹配
  • 列名是否匹配
  • 列类型是否兼容
  • NOT NULL 约束是否匹配
  • 主键约束是否匹配

如果验证失败,会返回 SchemaMismatch 错误。

删除表

db.drop_table::<User>().await?;

生成 SQL:

DROP TABLE IF EXISTS users

最佳实践

1. 为模型派生常用 Trait

#[derive(Debug, Model, Clone, PartialEq)]
struct User {
    // ...
}
  • Debug - 调试输出
  • Clone - 克隆支持
  • PartialEq - 比较支持 (测试时有用)

2. 使用有意义的表名

// ✅ 推荐: 复数形式
#[table = "users"]
#[table = "blog_posts"]
#[table = "user_roles"]

// ❌ 避免: 单数或不一致
#[table = "user"]
#[table = "User"]

3. 合理使用索引

// ✅ 为经常查询的字段添加索引
#[index]
status: String,

#[index]
created_at: String,

// ❌ 不要为所有字段添加索引

4. 使用 Option 表示可选数据

// ✅ 明确表达字段可以为空
email: Option<String>,

// ❌ 使用空字符串表示无值
email: String,  // 可能需要 "" 表示空
Prev
快速开始
Next
数据库连接