SeaORM简介
SeaORM 是一个关系型 ORM,用于帮助你像使用动态语言那样,在 Rust 中构建 Web 服务。实现所需的Trait以及创建并插入测试数据
在使用 SeaORM 之前,需要进行一些初始操作。本章我们将创建数据表、导入初始示例数据以及实现所需的 trait。最后,我们通过查询所有分类列表来验证这些操作是否正常运行。使用 SeaORM 查询数据
本章我们将讨论如何使用 SeaORM 进行查询:查询条件、分页、查询单条记录等。使用 SeaORM 插入数据
本章将讨论如何使用 SeaORM 添加记录。使用 SeaORM 修改数据
本章讨论使用 SeaORM 修改数据使用 SeaORM 删除数据
本章将讨论如何使用 SeaORM 实现删除。使用 SeaORM 操作一对多和多对一关系
正如其名,关系型数据库中的“关系”是很重要的部分。SeaORM 支持常见的数据关系,本章将讨论其中的一对多和多对一关系。SeaORM 的命令行工具和自动迁移
SeaORM 提供了一个命令行工具,可以快速生成实体。同时,还提供了自动迁移功能。SeaORM 操作多对多关系
本章将讨论多对多:一篇文章可以有多个标签,同样的,一个标签可以对应多篇文章。总结与作业
总结与作业
实现所需的Trait以及创建并插入测试数据
- 252510
- 2022-05-31 17:49:24
准备数据
请创建一个 PostgreSQL 数据库,并将以下SQL导入其中:
CREATE TABLE categoies ( -- 分类
id SERIAL PRIMARY KEY, -- 自增主键
name VARCHAR(20) NOT NULL UNIQUE, -- 分类名称
is_del BOOLEAN NOT NULL DEFAULT FALSE -- 是否删除
);
CREATE TABLE articles ( -- 文章
id SERIAL PRIMARY KEY, -- 自增主键
category_id INT NOT NULL REFERENCES categoies(id), -- 文章所属分类的ID,外键
title VARCHAR(255) NOT NULL, -- 文章标题
content TEXT NOT NULL, -- 文章内容
dateline TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 添加时间
is_del BOOLEAN NOT NULL DEFAULT FALSE -- 是否删除
);
-- 插入示例数据
INSERT INTO categoies (id,name) VALUES
(1,'Rust'), (2,'Go'), (3,'Javascript');
编写实体并实现所需的 trait
// src/entity/category.rs
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "categoies")]
pub struct Model {
#[sea_orm(primary_key)]
#[serde(skip_deserializing)]
pub id: i32,
pub name: String,
pub is_del: bool,
}
#[derive(Debug, Clone, Copy, EnumIter)]
pub enum Relation {}
impl RelationTrait for Relation {
fn def(&self) -> sea_orm::RelationDef {
panic!("没有定义关系")
}
}
impl ActiveModelBehavior for ActiveModel {}
SeaORM 的实体和 Rust 的模块
SeaORM 将每一个数据表抽象成一个实体,而在 Rust 中,通常使用模块来表示实体。
通常,每个实体都会包含 Entity
、 Model
、Relation
和ActiveModel
。
Entity
用于操作数据库。
Model
用于定义数据表中的字段与Rust数据结构的映射关系。同时,在 SELECT
操作时,返回的也是 Model
的实例。
Relation
用于定义数据表之间的关系。目前,我们不作任何定义,而是直接抛出一个panic
ActiveModel
也是数据表中字段与 Rust 数据结构的映射,不同于 Model
的是,ActiveModel
用于“写”操作,比如 UPDATE
、DELETE
等。
等等,这个 ActiveModel
是怎么来的?参考源码 可以发现,DeriveEntityModel
这个 derive 根据我们定义的Model
,生成了包括 ActiveModel
在内的多个数据结构
DeriveEntityModel
这是一个【全能】的派生宏,它主要用于从指定的Model
中,生成以下数据结构:
Entity
ActiveModel
Column
PrimaryKey
配置文件
WEB.ADDR=127.0.0.1:9527
DB.DSN="postgres://<用户名>:<密码>@pg.axum.rs:5432/axum_rs_seaorm"
共享状态结构体
// src/state.rs
use sea_orm::DatabaseConnection;
pub struct AppState {
pub conn: DatabaseConnection,
}
给路由加上共享状态
// src/main.rs
dotenv().ok();
let cfg = config::Config::from_env().unwrap();
let conn = Database::connect(&cfg.db.dsn).await.unwrap();
let app = router::init().layer(Extension(Arc::new(state::AppState { conn })));
实现分类列表功能
从共享状态中获取数据库连接
// src/handler/mod.rs
fn get_conn<'a>(state: &'a AppState) -> &'a DatabaseConnection {
&state.conn
}
从数据库中获取所有分类
我们重点来看这段代码:
let categies: Vec<category::Model> = category::Entity::find()
.order_by_asc(category::Column::Id)
.all(conn)
.await
.map_err(AppError::from)?;
category::Entity::find() -> Select<E>
构造一个用于查询的Select<E>
对象。
Select<E>
用于执行数据库SELECT
操作的对象。
order_by_asc()
指定用于升序排序的字段。
指定字段名
all()
获取所有数据
将数据记录填充到视图中
// src/view.rs
#[derive(Template)]
#[template(path = "category.html")]
pub struct CategoryTemplate {
pub categies: Vec<entity::category::Model>,
}
模板渲染
<!-- templates/category.html -->
<table class="table">
<thead>
<tr>
<th>#</th>
<th>名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for category in categies %}
<tr>
<td>{{ category.id }}</td>
<td>{{ category.name }}</td>
<td>
<a href="/category/edit/{{ category.id }}" class="btn btn-primary btn-sm">修改</a>
<a href="/category/del/{{ category.id }}" class="btn btn-danger btn-sm" onclick="return confirm('确定删除“{{ category.name }}”?')">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
本章效果
本章代码位于01/实现trait及插入示例数据分支