SeaORM 是一种关系 ORM,可帮助您使用
熟悉的动态语言在 Rust 中构建 Web 服务。
SeaORM 的官方文档在他们的官方网站上。
本指南使用的是 PostgreSQL。在我们开始之前,请确保您
已经为您的系统安装了PostgreSQL。
在本次教程中,我们将构建每个 CRUD 操作的简单示例。
我正在使用Rust v1.62 和sea-orm
v0.9
cargo new seaorm_demo --lib
cd seaorm_demo
首先,让我们将 SeaORM 和 tokio 添加到我们的依赖项中。
文件:Cargo.toml
[dependencies]
tokio = { version = "1.20", features = ["macros", "rt-multi-thread"] }
[dependencies.sea-orm]
version = "0.9"
features = [ "sqlx-postgres", "runtime-tokio-rustls", "macros" ]
default-features = false
cargo install sea-orm-cli
我们将编写一个迁移文件来设置我们的数据库和表模式。
sea-orm-cli migrate init
接下来会生成一个名为migration的目录
现在我们的项目结构应该是这样的。
.
├── Cargo.lock
├── Cargo.toml
├── migration
│ ├── Cargo.toml
│ ├── README.md
│ └── src
│ ├── lib.rs
│ ├── m20220101_000001_create_table.rs
│ └── main.rs
└── src
└── lib.rs
打开文件migration/Cargo.toml
并取消最后两行注释sea-orm-migration
.
文件:migration/Cargo.toml
[dependencies.sea-orm-migration]
version = "^0.9.0"
features = [
# Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI.
# View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime.
# e.g.
"runtime-tokio-rustls", # `ASYNC_RUNTIME` featrure
"sqlx-postgres", # `DATABASE_DRIVER` feature
]
migration/src/m20220101_000001_create_table.rs
在您喜欢的编辑器中编辑文件
并删除两个 “todo!()"
保存。
在项目根目录新建一个".env"文件
DATABASE_URL="postgres://root:root@localhost:5432/axum_example"
接下来,我们将运行迁移。
sea-orm-cli migrate up
它将编译migration
模块并运行您的迁移。在此之后,您
应该会在您的目录中看到一个名为 posts.pdb的文件。
创建一个新entity
模块。
cargo new entity --lib
接下来,生成实体。
sea-orm-cli generate entity -o entity/src
将sea-orm
依赖项添加到entity
模块。
文件:entity/Cargo.toml
[dependencies]
sea-orm = { version = "0.9" }
生成的实体应如下所示。
文件:entity/src/post.rs
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.0
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "post")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub title: String,
pub text: String,
}
#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
panic!("No RelationDef")
}
}
impl ActiveModelBehavior for ActiveModel {}
由于模块entity
位于我们项目的根目录,我们将lib.rs删除掉,然后把mod.rs转换
为库,以便我们可以使用它。
重命名entity/src/mod.rs
为entity/src/lib.rs
.
mv entity/src/mod.rs entity/src/lib.rs
接下来,我们将entity
和migration
库添加到
根项目的依赖项中。
文件:Cargo.toml
[workspace]
members = [".", "entity", "migration"]
[dependencies]
entity = { path = "entity" }
migration = { path = "migration" }
现在你的项目结构应该看起来像这样的
.
├── Cargo.lock
├── Cargo.toml
├── entity
│ ├── Cargo.toml
│ └── src
│ ├── lib.rs
│ ├── post.rs
│ └── prelude.rs
├── migration
│ ├── Cargo.lock
│ ├── Cargo.toml
│ ├── README.md
│ └── src
│ ├── lib.rs
│ ├── m20220101_000001_create_table.rs
│ └── main.rs
├── src
│ └── lib.rs
└── migration.pdb
项目Cargo.toml
应该如下所示。
文件:Cargo.tmol
[package]
name = "seaorm_demo"
version = "0.1.0"
edition = "2021"
[workspace]
members = [".", "entity", "migration"]
[dependencies]
entity = { path = "entity" }
migration = { path = "migration" }
tokio = { version = "1.20", features = ["macros", "rt-multi-thread"] }
[dependencies.sea-orm]
version = "0.9"
features = [ "sqlx-postgres", "runtime-tokio-rustls", "macros" ]
default-features = false
现在我们编写代码来建立与数据库的连接。
文件:src/lib.rs
use migration::{DbErr, Migrator, MigratorTrait};
use sea_orm::{Database, DbConn};
const DATABASE_URL: &str = "postgres://root:root@localhost:5432/axum_example";
pub async fn establish_connection() -> Result<DbConn, DbErr> {
let db = Database::connect(DATABASE_URL)
.await
.expect("连接数据库失败");
Migrator::up(&db, None)
.await
.expect("迁移失败");
Ok(db)
}
现在让我们编写一些代码来创建帖子。创建一个新文件src/bin/create_post.rs
。
文件:src/bin/create_post.rs
use migration::DbErr;
use sea_orm::{Set, ActiveModelTrait};
use seaorm_demo::establish_connection;
use entity::post;
#[tokio::main]
async fn main() -> Result<(), DbErr>{
let db = establish_connection().await?;
let post = post::ActiveModel {
title: Set(String::from("我是title")),
text: Set(String::from("我是text")),
..Default::default()
};
let post: post::Model = post.insert(&db).await?;
println!("ID: {}, title: {}", post.id, post.title);
Ok(())
}
我们可以如下运行我们的新脚本。
cargo run --bin create_post
应该如下所示。
$ cargo run --bin create_post
Compiling seaorm_demo v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 3.85s
Running `target/debug/create_post`
ID: 1, title: 我是title
如果您希望在数据库中创建更多条目,请更改标题/文本create_post.rs
并再次执行脚本。
我会再创造一个。
$ cargo run --bin create_post
Compiling seaorm_demo v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 4.08s
Running `target/debug/create_post`
ID: 2, title: 我是title
接下来,我们编写读取数据库中所有帖子的示例。
文件:src/bin/read_posts.rs
use migration::DbErr;
use sea_orm::EntityTrait;
use seaorm_demo::establish_connection;
use entity::post;
#[tokio::main]
async fn main() -> Result<(), DbErr>{
let db = establish_connection().await?;
let posts: Vec<post::Model> = post::Entity::find().all(&db).await?;
println!("表中的所有帖子:");
for post in posts {
println!("id: {}, title: {}", post.id, post.title);
}
Ok(())
}
就像之前一样,您可以按如下方式运行这个新文件。
cargo run --bin read_posts
应该如下所示。
$ cargo run --bin read_posts
Compiling seaorm_demo v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 4.08s
Running `target/debug/read_posts`
表中的所有帖子:
ID: 1, title : 我是title
ID: 2, title : 我是title
现在,假设我们想要对帖子的标题执行 UPDATE 操作。
文件:src/bin/update_post.rs
use migration::DbErr;
use sea_orm::{EntityTrait, Set, ActiveModelTrait};
use seaorm_demo::establish_connection;
use entity::post;
#[tokio::main]
async fn main() -> Result<(), DbErr>{
let db = establish_connection().await?;
//根据ID更新帖子内容
let post = post::Entity::find_by_id(1).one(&db).await?;
let mut post: post::ActiveModel = post.unwrap().into();
post.title = Set("哈哈,我被更新啦".to_owned());
let post: post::Model = post.update(&db).await?;
println!("更新后的帖子id: {} title: {}", post.id, post.title);
Ok(())
}
我们运行这个脚本
cargo run --bin update_post
应该如下所示。
$ cargo run --bin update_post ⏎
Compiling seaorm_demo v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 2.80s
Running `target/debug/update_post`
更新后的帖子id:1 title: 哈哈,我被更新啦
现在进行最后的操作,删除。创建一个新文件src/bin/delete_post.rs
我们将删除 ID 为 1 的帖子
文件:src/bin/delete_post.rs
use migration::DbErr;
use sea_orm::{EntityTrait, DeleteResult, ModelTrait};
use seaorm_demo::establish_connection;
use entity::post;
#[tokio::main]
async fn main() -> Result<(), DbErr>{
let db = establish_connection().await?;
let post = post::Entity::find_by_id(1).one(&db).await?;
let post: post::Model = post.unwrap();
let res: DeleteResult = post.delete(&db).await?;
assert_eq!(res.rows_affected, 1);
println!("{:?}", res);
Ok(())
}
我们将调用这个脚本
cargo run --bin delete_post
应该如下所示。
$ cargo run --bin delete_post
Compiling seaorm_demo v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 5.42s
Running `target/debug/delete_post`
DeleteResult { rows_affected: 1 }
我们可以再次执行脚本read_post
来查看数据库中还有哪些帖子。
$ cargo run --bin read_posts
Finished dev [unoptimized + debuginfo] target(s) in 0.31s
Running `target/debug/read_posts`
ID: 2, title: 我是title