Skip to content

sea-orm-cli generation doesn't support multi-column foreign keys #855

@oersted

Description

@oersted

Description

For single-column foreign keys, the generated parent and child have a relation to each other. The parent has a simple has_many and the child has a belong_to with the details of the foreign key columns and on update/delete policies.

For multi-column foreign keys though, it generates one belongs_to relation on the child per column and doesn't generate a has_many relation on the parent. Therefore, for example, using find_with_related doesn't compile.

Steps to Reproduce

#[derive(Iden)]
enum Block {
    Table,
    Qidx,
    Bidx,
}

#[derive(Iden)]
enum Rule {
    Table,
    Qidx,
    Bidx,
    Ridx,
}

#[async_trait::async_trait]
impl MigrationTrait for Migration {
    async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
        manager
            .create_table(Table::create()
                .table(Block::Table)
                .if_not_exists()
                .col(ColumnDef::new(Block::Qidx).big_unsigned().not_null())
                .col(ColumnDef::new(Block::Bidx).big_unsigned().not_null())
                .primary_key(Index::create()
                    .name("PK-block")
                    .col(Rule::Qidx).col(Rule::Bidx)
                    .primary())
                .to_owned())
            .await?;

        manager
            .create_table(Table::create()
                .table(Rule::Table)
                .if_not_exists()
                .col(ColumnDef::new(Rule::Qidx).big_unsigned().not_null())
                .col(ColumnDef::new(Rule::Bidx).big_unsigned().not_null())
                .col(ColumnDef::new(Rule::Ridx).big_unsigned().not_null())
                .primary_key(Index::create()
                    .name("PK-rule")
                    .col(Rule::Qidx).col(Rule::Bidx).col(Rule::Ridx)
                    .primary())
                .foreign_key(ForeignKey::create()
                    .name("FK-rule-block")
                    .from(Rule::Table, (Rule::Qidx, Rule::Bidx))
                    .to(Block::Table, (Block::Qidx, Block::Bidx))
                    .on_delete(ForeignKeyAction::Cascade)
                    .on_update(ForeignKeyAction::Restrict))
                .to_owned())
            .await?;
    }

It will generate both of these files.

//! SeaORM Entity. Generated by sea-orm-codegen 0.8.0

use sea_orm::entity::prelude::*;

#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "block")]
pub struct Model {
    #[sea_orm(primary_key, auto_increment = false)]
    pub qidx: i32,
    #[sea_orm(primary_key, auto_increment = false)]
    pub bidx: i32,
}

impl ActiveModelBehavior for ActiveModel {}
//! SeaORM Entity. Generated by sea-orm-codegen 0.8.0

use sea_orm::entity::prelude::*;

#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "rule")]
pub struct Model {
    #[sea_orm(primary_key, auto_increment = false)]
    pub qidx: i32,
    #[sea_orm(primary_key, auto_increment = false)]
    pub bidx: i32,
    #[sea_orm(primary_key, auto_increment = false)]
    pub ridx: i32,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
    #[sea_orm(
        belongs_to = "super::block::Entity",
        from = "Column::Qidx",
        to = "super::block::Column::Qidx",
        on_update = "Restrict",
        on_delete = "Cascade"
    )]
    Block2,
    #[sea_orm(
        belongs_to = "super::block::Entity",
        from = "Column::Bidx",
        to = "super::block::Column::Bidx",
        on_update = "Restrict",
        on_delete = "Cascade"
    )]
    Block1,
}

impl ActiveModelBehavior for ActiveModel {}

Expected Behavior

It should generate a has_many relation on Block pointing to Rule. Simply adding this by hand doesn't trivially work, I'm unsure how the Related trait should be implemented for a double relation like Block1 and Block2, is the relation on the child even correct?

Even if the support for this in the generation is not implemented in the short term, I would really appreciate some guidance on how to define the Entity manually so that this works as intended.

Versions

sea-orm 0.8.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-schemaArea: schema discovery

    Projects

    Status

    Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions