Skip to content

in entity first schema sync does not sync existing foreign key actions #2953

@wumtdev

Description

@wumtdev

Description

In Entity First workflow you can specify on_delete action on relations.
Schema sync will specify this action on foreign key creation.
But if foreign key already exists in database it won't change it if it was changed in schema, so if you've changed action in entity definition it won't be applied by schema sync.

Steps to Reproduce

  1. Setup Entity First workflow with sqlite file database
  2. Define two entities with relation:
mod role {
    use super::role_permission;
    use sea_orm::entity::prelude::*;
    #[sea_orm::model]
    #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
    #[sea_orm(table_name = "role")]
    pub struct Model {
        #[sea_orm(primary_key)]
        pub id: u32,
        pub name: String,

        #[sea_orm(has_many)]
        pub permissions: HasMany<role_permission::Entity>,
    }

    impl ActiveModelBehavior for ActiveModel {}
}

mod role_permission {
    use super::role;
    use sea_orm::entity::prelude::*;

    #[sea_orm::model]
    #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
    #[sea_orm(table_name = "role_permission")]
    pub struct Model {
        #[sea_orm(primary_key, auto_increment = false)]
        pub role_id: u32,
        #[sea_orm(primary_key, auto_increment = false)]
        pub name: String,

        #[sea_orm(belongs_to, from = "role_id", to = "id")]
        pub role: HasOne<role::Entity>,
    }

    impl ActiveModelBehavior for ActiveModel {}
}
  1. Launch schema sync, so it will create database
  2. Add foreign key on delete action in entity definition:
#[sea_orm(belongs_to, from = "role_id", to = "id", on_delete = "Cascade")]
pub role: HasOne<role::Entity>,
  1. Launch schema sync, it won't change action of foreign key existing in database
  2. Check foreign key in database viewer sqlite3 database.sqlite ".schema role_permission" or try to create role with permissions and then delete this role, sqlite will return error "FOREIGN KEY constraint failed" even though the foreign key action on_delete = "Cascade" is specified in entity definition:
role::ActiveModelEx {
    id: Set(1u32),
    name: Set("admin".into()),
    permissions: sea_orm::HasManyModel::Replace(vec![
        role_permission::ActiveModelEx {
            name: Set("moderate".into()),
            ..Default::default()
        },
        role_permission::ActiveModelEx {
            name: Set("ban".into()),
            ..Default::default()
        },
    ]),
    ..Default::default()
}
    .insert(&db)
    .await
    .unwrap();

role::Entity::delete_by_id(1u32).exec(&db).await.unwrap();
// Exec(SqlxError(Database(SqliteError { code: 787, message: "FOREIGN KEY constraint failed" })))
  1. If you delete database file and then sync schema, it will apply on delete foreign key action and delete in code snippet above will work without errors and in database schema view will appear foreign key on delete action

Expected Behavior

Schema sync should have monitored on delete action in existing foreign key, compared with schema and changed it.

Actual Behavior

Schema sync ignored foreign key on delete action change.

Reproduces How Often

Reproducible when you forgot to add foreign key on delete action.

Workarounds

Delete database file if there's no important data, so sync will create foreign key from scratch.
Or change it manually using database viewer.

Versions

sea-orm = { version = "2.0.0-rc.32", features = [
    "sqlx-sqlite",
    "runtime-tokio-rustls",
    "macros",
    "debug-print",
    "schema-sync",
    "entity-registry",
] }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions