rust SeaORM使用示例
2026/8/10 13:37:48 网站建设 项目流程

下面通过一个完整的示例,演示如何使用 SeaORM 对 PostgreSQL 数据库进行增删改查(CRUD)操作。

1. 项目设置与依赖

首先,创建一个新项目并添加必要的依赖。

bash

cargo new seaorm-example && cd seaorm-example

Cargo.toml中添加以下依赖:

toml

[dependencies] # SeaORM 核心库,启用 "sqlx-postgres" 特性以支持 PostgreSQL 和异步运行时 sea-orm = { version = "1.0", features = ["sqlx-postgres", "runtime-tokio-rustls"] } # 异步运行时 tokio = { version = "1", features = ["full"] } # 用于处理异步错误 anyhow = "1" # 可选:用于记录日志 env_logger = "0.10"

2. 定义实体 (Entity)

SeaORM 鼓励“实体优先”的工作流。我们手动定义一个bakery实体,它对应数据库中的bakery表。

创建文件src/entities/bakery.rs

rust

// src/entities/bakery.rs use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "bakery")] pub struct Model { #[sea_orm(primary_key)] pub id: i32, pub name: String, #[sea_orm(column_type = "Double")] pub profit_margin: f64, } #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] pub enum Column { Id, Name, ProfitMargin, } #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] pub enum PrimaryKey { Id, } impl PrimaryKeyTrait for PrimaryKey { type ValueType = i32; fn auto_increment() -> bool { true } } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} impl Related<super::chef::Entity> for Entity { fn to() -> RelationDef { // 我们稍后会定义 chef 实体 todo!() } } impl ActiveModelBehavior for ActiveModel {}

为了让bakery模块可用,在src/entities/mod.rs中声明它:

rust

// src/entities/mod.rs pub mod bakery;

3. 数据库连接与初始化

src/main.rs中,我们建立数据库连接,并创建一个bakery表(如果它不存在的话)。SeaORM 可以通过Schema工具从实体定义创建表。

rust

// src/main.rs mod entities; use entities::bakery; use sea_orm::{ ColumnTrait, ConnectionTrait, Database, DbBackend, DbErr, EntityTrait, QueryFilter, Schema, Set, ActiveValue::NotSet }; use anyhow::Result; #[tokio::main] async fn main() -> Result<()> { // 初始化日志(可选) env_logger::init(); // 1. 建立数据库连接 let database_url = "postgres://postgres:password@localhost:5432/postgres"; let db = Database::connect(database_url).await?; // 2. 创建表(如果表不存在) let schema = Schema::new(DbBackend::Postgres); let create_table_stmt = schema.create_table_from_entity(bakery::Entity); // 执行创建表的SQL语句 match db.execute(db.get_database_backend().build(&create_table_stmt)).await { Ok(_) => println!("Table 'bakery' created or already exists."), Err(e) => eprintln!("Error creating table: {}", e), }; // 3. 执行CRUD操作 run_crud_operations(&db).await?; Ok(()) }

4. 执行 CRUD 操作

定义run_crud_operations函数,在其中演示增、查、改、删操作。

rust

async fn run_crud_operations(db: &sea_orm::DatabaseConnection) -> Result<(), DbErr> { // --- 插入 (Insert) --- // 使用 ActiveModel 构建要插入的数据[reference:4] let happy_bakery = bakery::ActiveModel { name: Set("Happy Bakery".to_owned()), profit_margin: Set(0.0), ..Default::default() // 其他字段(如 id)使用默认值 }; let insert_result = Bakery::insert(happy_bakery).exec(db).await?; let new_bakery_id = insert_result.last_insert_id; println!("插入成功,ID: {}", new_bakery_id); // --- 查询 (Select) --- // 1. 查询所有[reference:5] let all_bakeries: Vec<bakery::Model> = Bakery::find().all(db).await?; println!("所有面包店: {:?}", all_bakeries); // 2. 根据主键查询[reference:6] let bakery_by_id: Option<bakery::Model> = Bakery::find_by_id(new_bakery_id).one(db).await?; if let Some(bakery) = bakery_by_id { println!("根据ID查询结果: {:?}", bakery); } // 3. 带条件查询[reference:7] let sad_bakery: Option<bakery::Model> = Bakery::find() .filter(bakery::Column::Name.eq("Sad Bakery")) .one(db) .await?; if let Some(bakery) = sad_bakery { println!("根据名字 'Sad Bakery' 查询结果: {:?}", bakery); } // --- 更新 (Update) --- // 1. 先查询出要更新的模型,然后转换为 ActiveModel[reference:8] let mut sad_bakery_active: bakery::ActiveModel = Bakery::find_by_id(new_bakery_id) .one(db) .await? .unwrap() // 为了演示,假设一定存在 .into(); // 将 Model 转换为 ActiveModel // 修改字段值 sad_bakery_active.name = Set("Sad Bakery".to_owned()); // 执行更新 let updated_bakery: bakery::Model = sad_bakery_active.update(db).await?; println!("更新后的数据: {:?}", updated_bakery); // 2. 批量更新[reference:9] use sea_orm::{QueryFilter, Condition}; let update_result = Bakery::update_many() .col_expr(bakery::Column::ProfitMargin, sea_orm::Expr::value(10.0)) .filter(bakery::Column::Name.contains("Sad")) .exec(db) .await?; println!("批量更新影响行数: {}", update_result.rows_affected); // --- 删除 (Delete) --- // 根据条件删除[reference:10] let delete_result = Bakery::delete_many() .filter(bakery::Column::Name.eq("Sad Bakery")) .exec(db) .await?; println!("删除影响行数: {}", delete_result.rows_affected); Ok(()) }

5. 高级特性示例

关联查询 (Relations)

SeaORM 支持定义实体间的关系,并能进行懒加载(Lazy Loading)和预加载(Eager Loading)。

rust

// 假设已定义 cake 和 fruit 实体,且 cake 与 fruit 是一对多关系 // 懒加载:先查 Cake,再查其关联的 Fruit[reference:12] let cheese_cake: Option<cake::Model> = Cake::find_by_id(1).one(db).await?; if let Some(cake) = cheese_cake { let fruits: Vec<fruit::Model> = cake.find_related(fruit::Entity).all(db).await?; println!("Cake's fruits: {:?}", fruits); } // 预加载:一次性查询 Cake 及其关联的 Fruit[reference:13] let cakes_with_fruits: Vec<(cake::Model, Vec<fruit::Model>)> = Cake::find().find_with_related(fruit::Entity).all(db).await?;
事务 (Transactions)

SeaORM 通过DatabaseTransaction支持事务。

rust

use sea_orm::{TransactionTrait}; let txn = db.begin().await?; // 在事务内执行多个操作... let bakery = bakery::ActiveModel { /* ... */ }.insert(&txn).await?; // ... 其他操作 txn.commit().await?; // 提交事务 // 或 txn.rollback().await?; // 回滚事务
嵌套 ActiveModel (Nested ActiveModel)

SeaORM 2.0 引入的Nested ActiveModel允许你一次性保存一个包含关联数据的复杂对象树。例如,一次性插入一个用户及其个人资料、帖子和标签。

rust

let user = user::ActiveModel::builder() .set_name("Bob") .set_email("bob@sea-ql.org") .set_profile(profile::ActiveModel::builder().set_picture("image.jpg")) .add_post( post::ActiveModel::builder() .set_title("Nice weather") .add_tag(tag::ActiveModel::builder().set_tag("sunny")), ) .save(db) .await?;

总结

这个示例涵盖了 SeaORM 的核心用法:

  • 实体定义:使用#[derive(DeriveEntityModel)]等宏将 Rust 结构体映射到数据库表。

  • 数据库连接:通过Database::connect创建连接池。

  • 增删改查 (CRUD):通过EntityActiveModel提供的insertfindupdatedelete等方法进行操作。

  • 高级功能:支持关联查询、事务和嵌套 ActiveModel。

SeaORM 的官方文档非常详尽,包含了从安装到高级特性的完整指南。你可以将其作为后续深入学习的参考。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询