Skip to main content
Version: 1.2.x 🚧

Expanded Entity Structure

SeaORM is dynamic, which means you have the flexibility to configure things on runtime. If you are curious what DeriveEntityModel expands into, read along. Otherwise, you can skip this for now.

The expanded entity format can be generated by sea-orm-cli with the --expanded-format option.

Let's go through the sections of the expanded Cake entity.

Entity

By implementing the EntityTrait, you can perform CRUD operations on the given table.

#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;

impl EntityName for Entity {
fn schema_name(&self) -> Option<&str> {
None
}

fn table_name(&self) -> &str {
"cake"
}
}

Column

An enum representing all columns in this table.

#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Id,
Name,
}

impl ColumnTrait for Column {
type EntityName = Entity;

fn def(&self) -> ColumnDef {
match self {
Self::Id => ColumnType::Integer.def(),
Self::Name => ColumnType::String(None).def(),
}
}
}

All column names are assumed to be in snake-case. You can override the column name by specifying the column_name attribute.

pub enum Column {
Id, // maps to "id" in SQL
Name, // maps to "name" in SQL
#[sea_orm(column_name = "create_at")]
CreateAt // maps to "create_at" in SQL
}

To specify the datatype of each column, the ColumnType enum can be used.

Additional properties

  • Default Value
  • Unique
  • Indexed
  • Nullable
ColumnType::String(None).def().default_value("Sam").unique().indexed().nullable()

Cast Column Type on Select and Save

If you need to select a column as one type but save it into the database as another, you can override the select_as and the save_as methods to perform the casting. A typical use case is selecting a column of type citext (case-insensitive text) as String in Rust and saving it into the database as citext. One should override the ColumnTrait's methods as below:

use sea_orm::sea_query::{Expr, SimpleExpr, Alias}

impl ColumnTrait for Column {
// Snipped...

/// Cast column expression used in select statement.
fn select_as(&self, expr: Expr) -> SimpleExpr {
match self {
Column::CaseInsensitiveText => expr.cast_as(Alias::new("text")),
_ => self.select_enum_as(expr),
}
}

/// Cast value of a column into the correct type for database storage.
fn save_as(&self, val: Expr) -> SimpleExpr {
match self {
Column::CaseInsensitiveText => val.cast_as(Alias::new("citext")),
_ => self.save_enum_as(val),
}
}
}

Primary Key

An enum representing the primary key of this table. A composite key is represented by an enum with multiple variants.

ValueType defines the type of last_insert_id in InsertResult.

auto_increment defines whether the primary key has an auto-generated value.

#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
#[sea_orm(column_name = "id")] // Override the default column name
Id, // maps to "id" in SQL
}

impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;

fn auto_increment() -> bool {
true
}
}

Example composite key

pub enum PrimaryKey {
CakeId,
FruitId,
}

impl PrimaryKeyTrait for PrimaryKey {
type ValueType = (i32, i32);

fn auto_increment() -> bool {
false
}
}

Model

The Rust struct for storing query results.

#[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
pub struct Model {
pub id: i32,
pub name: String,
}

Nullable Attribute

If the table column is nullable, wrap it with an Option.

pub struct Model {
pub id: i32,
pub name: Option<String>,
}

Active Model

An ActiveModel has all the attributes of its corresponding Model but all attributes are wrapped in an ActiveValue.

#[derive(Clone, Debug, PartialEq)]
pub struct ActiveModel {
pub id: ActiveValue<i32>,
pub name: ActiveValue<Option<String>>,
}

Relation

Specifying the relations with other entities.

#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {
Fruit,
}

impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
}
}
}

Defining trait bounds to help you query related entities together, especially helpful in many-to-many relations.

impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}

impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}

fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}