SeaORM 是一种关系 ORM,可帮助您使用
熟悉的动态语言在 Rust 中构建 Web 服务。
SeaORM 的官方文档在他们的官方网站上。
本指南使用的是 PostgreSQL。在我们开始之前,请确保您
已经为您的系统安装了PostgreSQL。
在本次教程中,我们将构建每个 CRUD 操作的简单示例。
我正在使用Rust v1.62 和sea-ormv0.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
{ - 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::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