Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

初始化数据

如何在数据库迁移过程中 初始化数据(Seeding Data) 。当你建好表后,通常需要塞入一些初始数据(如默认管理员、配置项等)。


1. 数据初始化 (Seeding Data) 的三种方式

  • 使用 ActiveModel 初始化 : 借用已经定义好的 Rust 实体类来插入数据,具有最强的类型安全性:
let db = manager.get_connection();
cake::ActiveModel { 
   name: Set(
       "Cheesecake".to_owned()), 
       ..Default::default() 
   }
  .insert(db)
   .await?;
  • 使用 SeaQuery 语句初始化 : 不需要依赖具体的实体类,直接通过代码构造插入语句,适合在实体类尚未生成时使用, eg:
let stmt = Query::insert()
      .into_table("cake")
      .columns(["name"])
      .values_panic(["Tiramisu".into()])
      .to_owned();
manager.execute(&stmt).await?;
  • 事务式初始化 (Transactional) : 手动开启一个事务,确保数据插入要么全部成功,要么全部回滚,保证数据的一致性, eg:
let db = manager.get_connection();
let txn = db.begin().await?; // 开启事务
cake::ActiveModel {
    name: Set("Cheesecake".to_owned()),
    ..Default::default()
}
.insert(&txn)
.await?;
txn.commit().await?; // 提交事务

2. 深度细节解析

① 为什么使用 ActiveModel

这是最推荐的方式。因为它是强类型的,如果你的数据库字段改了,这段代码在编译阶段就会报错,而不是等到运行时才崩溃。

注意 :这要求你的 migration crate 能够引用到 entity crate。

② 为什么使用 SeaQuery

如果你在写迁移脚本时,还没生成对应的 entity 代码,或者不想让迁移脚本和业务代码耦合得太深,就可以用 Query::insert()。它直接操作字符串表名和列名,灵活性更高。

③ 关于 PostgreSQL 的事务 (Important!)

你使用的是 PostgreSQL ,有一个非常大的优势:

  • 自动事务 :SeaORM 在 Postgres 上运行 up 函数时,默认会把整个函数包裹在一个事务里。
  • 手动事务的作用 :虽然有自动事务,但文档中的 db.begin() 允许你在迁移逻辑内部进行更细粒度的控制,或者在复杂的逻辑中明确标注事务边界。

3. 核心 API 说明

  • manager.get_connection(): 从迁移管理器中获取当前的数据库连接对象 (DbConn)。
  • Query::insert(): SeaQuery 的插入语句构造器。
  • manager.execute(&stmt): 执行构造好的 SeaQuery 语句。
  • db.begin(): 在当前连接上开启一个异步事务。
  • txn.commit(): 提交事务,让所有更改永久生效。

迁移脚本不只是能改“结构(表)”,还能改“内容(数据)”。在 PostgreSQL 中,利用其原子性特点,结合 ActiveModel 的类型安全,你可以非常稳健地完成数据库的初始化。