SeaORM 2.0.0
SeaORM 2.0 is the first stable release of the 2.x line. It reworks how entities,
relations, and ActiveModels are defined and used, adds an entity-first workflow,
introduces role-based access control, and brings the library onto SeaQuery 1.0 and
SQLx 0.9.
The full, itemized changelog for the 2.0 series (all release candidates included)
is in CHANGELOG.md.
Highlights
New entity format
Relations are now declared directly on the Model struct with #[sea_orm::model],
replacing the separate Relation enum and Related impls.
#[sea_orm::model]
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "user")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
#[sea_orm(has_one)]
pub profile: HasOne<super::profile::Entity>,
#[sea_orm(has_many)]
pub posts: HasMany<super::post::Entity>,
}See the new entity format walk-through.
BelongsTo relation type with compile-time cardinality
A belongs_to relation can be typed BelongsTo<Entity> (required) or
BelongsTo<Option<Entity>> (optional), encoding the foreign-key cardinality in the
type and paired with the write-side ActiveBelongsTo. The macro validates the type
against the nullability of the from columns at compile time. BelongsTo is the
recommended type for belongs_to; the legacy HasOne<Entity> field type remains
supported for backward compatibility. (#3118)
Strongly-typed columns
Filter with the typed COLUMN constant for compile-time type safety, alongside the
existing Column enum.
user::Entity::find().filter(user::COLUMN.name.contains("Bob"))Nested ActiveModel
Build and persist an entity together with its related rows in one expression, and
push has-many children onto a loaded model.
let bob = user::ActiveModel::builder()
.set_name("Bob")
.set_email("bob@sea-ql.org")
.set_profile(profile::ActiveModel::builder().set_picture("Tennis"))
.insert(db)
.await?;See nested ActiveModel.
Entity Loader
Load an entity together with its relations, including nested relations, in a single
call.
let user = user::Entity::load()
.filter_by_id(12)
.with(profile::Entity)
.with((post::Entity, comment::Entity))
.one(db)
.await?;Entity-first workflow
Create tables directly from entity definitions via the schema registry, without
writing a migration first.
db.get_schema_registry("my_crate::*").sync(db).await?;See the entity-first workflow.
Role-Based Access Control
A table-scoped, hierarchical RBAC engine with a query auditor and a
RestrictedConnection that implements ConnectionTrait and enforces permissions on
all Entity operations (including complex joins, insert-select, and CTE queries).
(#2683)
Overhauled insert_many
insert_many no longer shares a helper struct with single insert. Panic-prone APIs
were removed, empty input returns None / vec![] on exec, and the new InsertMany
helper exposes last_insert_id: Option<Value>. (#2628)
Synchronous SeaORM
The sea-orm-sync crate provides a synchronous SeaORM backed by rusqlite, mirroring
the async API with async/await stripped away.
Upgrading from 1.x
Follow the 1.0 to 2.0 migration guide
and the 2.0 walk-through.
Notable breaking changes to be aware of:
- Expression methods like
.eq(),.like(),.contains()now require
use sea_orm::ExprTrait;in scope. Also read
SeaQuery's breaking changes. execute/query_one/query_all/streamnow take a SeaQuery statement; the
raw-SQL variants areexecute_raw/query_one_raw/query_all_raw/stream_raw.- PostgreSQL auto-increment columns now use
GENERATED BY DEFAULT AS IDENTITYinstead
ofserial; opt back in withoption-postgres-use-serialif needed. - SQLite maps both
IntegerandBigIntegertointeger. DeriveValueTypenow also derivesNotU8,IntoActiveValue, andTryFromU64;
remove any manual implementations to avoid conflicts.- Removed the
runtime-actixfeature alias (useruntime-tokio); removed
DeriveCustomColumnanddefault_as_str.
Dependencies
- SeaQuery 1.0
- SQLx 0.9
- sea-schema 0.18