Reputation: 174
I'm trying to create a many-to-many relationship in a SeaORM migration, but I'm facing an issue where the generated Related trait doesn't include the via method despite my attempts.
// We probebly don't even need this table, but Im adding it just for making calls to telegram fewer.
use sea_orm_migration::prelude::*;
use crate::{m20240303_000003_create_caller::Caller, m20240303_000006_create_profile::Profile};
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Group::Table)
.if_not_exists()
.col(
ColumnDef::new(Group::Id)
.big_integer()
.not_null()
.primary_key()
.unique_key(),
)
.col(ColumnDef::new(Group::ActiveProfile).integer().null())
.col(ColumnDef::new(Group::IsMixed).boolean().not_null())
.foreign_key(
ForeignKey::create()
.from(Group::Table, Group::ActiveProfile)
.to(Profile::Table, Profile::Id)
.on_delete(ForeignKeyAction::SetNull)
.on_update(ForeignKeyAction::Cascade),
)
.to_owned(),
)
.await?;
manager
.create_table(
Table::create()
.table(GroupCaller::Table)
.if_not_exists()
.primary_key(
Index::create()
.col(GroupCaller::GroupId)
.col(GroupCaller::CallerId),
)
.col(
ColumnDef::new(GroupCaller::GroupId)
.big_integer()
.not_null(),
)
.col(
ColumnDef::new(GroupCaller::CallerId)
.big_integer()
.not_null(),
)
.foreign_key(
ForeignKey::create()
.from(GroupCaller::Table, GroupCaller::GroupId)
.to(Group::Table, Group::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.foreign_key(
ForeignKey::create()
.from(GroupCaller::Table, GroupCaller::CallerId)
.to(Caller::Table, Caller::UserId)
.on_update(ForeignKeyAction::Cascade)
.on_delete(ForeignKeyAction::Cascade),
)
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(
Table::drop()
.table(Group::Table)
.table(GroupCaller::Table)
.to_owned(),
)
.await
}
}
#[derive(DeriveIden)]
pub enum Group {
Table,
/// Id of the group
Id,
/// Id of active profile if any
ActiveProfile,
/// Is the profile mixed? happen when safe
/// changing between profiles.
IsMixed,
}
#[derive(DeriveIden)]
pub enum GroupCaller {
Table,
GroupId,
CallerId,
}
group.rs
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.14
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "group")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: i64,
pub active_profile: Option<i32>,
pub is_mixed: bool,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::group_caller::Entity")]
GroupCaller,
#[sea_orm(
belongs_to = "super::profile::Entity",
from = "Column::ActiveProfile",
to = "super::profile::Column::Id",
on_update = "Cascade",
on_delete = "SetNull"
)]
Profile,
}
impl Related<super::group_caller::Entity> for Entity {
fn to() -> RelationDef {
Relation::GroupCaller.def()
}
}
impl Related<super::profile::Entity> for Entity {
fn to() -> RelationDef {
Relation::Profile.def()
}
}
impl Related<super::caller::Entity> for Entity {
fn to() -> RelationDef {
super::group_caller::Relation::Caller.def()
}
fn via() -> Option<RelationDef> {
Some(super::group_caller::Relation::Group.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}
group_caller.rs
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.14
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "group_caller")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub group_id: i64,
#[sea_orm(primary_key, auto_increment = false)]
pub caller_id: i64,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::caller::Entity",
from = "Column::CallerId",
to = "super::caller::Column::UserId",
on_update = "Cascade",
on_delete = "Cascade"
)]
Caller,
#[sea_orm(
belongs_to = "super::group::Entity",
from = "Column::GroupId",
to = "super::group::Column::Id",
on_update = "Cascade",
on_delete = "Cascade"
)]
Group,
}
impl Related<super::caller::Entity> for Entity {
fn to() -> RelationDef {
Relation::Caller.def()
}
}
impl Related<super::group::Entity> for Entity {
fn to() -> RelationDef {
Relation::Group.def()
}
}
impl ActiveModelBehavior for ActiveModel {}
Am I missing something in my approach? What steps are necessary to establish a many-to-many relationship within a SeaORM migration, including generating the via method in the Related trait?
Upvotes: 2
Views: 941
Reputation: 111
You’re doing right except one thing. The junction table should respect following requirements, it should have:
For example you should add the primary key to the junction table like this:
.primary_key(
Index::create()
.table(UserRole::Table)
.col(UserRole::UserId)
.col(UserRole::RoleId),
)
Upvotes: 1