sea-orm icon indicating copy to clipboard operation
sea-orm copied to clipboard

`AttrNotSet` error when using `.try_into_model()` even though the attribute listed is optional

Open PacificBird opened this issue 1 month ago • 2 comments

Description

When creating models as mock inputs for testing purposes, I am creating an ActiveModel with only the non-nullable fields filled out and using default to make the rest NotSet, then using .try_into_model() to convert that into a model (which is required by my function). When I run the test, I get an AttrNotSet error complaining that I haven't set the optional fields, even though these should default to None.

Steps to Reproduce

Model definition:

#[sea_orm::model]
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "stations_creston")]
pub struct Model {
    #[sea_orm(primary_key, auto_increment = false)]
    pub station_id: i32,
    #[sea_orm(unique)]
    pub network_id: String,
    pub station_name: String,
    pub installation_date: Option<TimeDate>,
}

It should also be noted that installation_date is set to nullable in my MySQL database, and the default value is set to NULL

Test setup

let test_station = stations_creston::ActiveModel {
    station_id: ActiveValue::Set(628),
    network_id: ActiveValue::Set("CRESNEKN".to_owned()),
    station_name: ActiveValue::Set("example".to_owned()),
    ..Default::default()
}
.try_into_model()
.expect("couldn't make test station model");

Expected Behavior

This shouldn't panic

Actual Behavior

The following panic is produced:

thread 'apis::creston::test::get_data' panicked at src/apis/creston.rs:181:10:
couldn't make test station model: AttrNotSet("installation_date")

Reproduces How Often

Happens every time

Versions

SeaOrm 2.0.0-rc.18 cargo 1.93.0-nightly Void Linux

PacificBird avatar Dec 02 '25 01:12 PacificBird

The API has always been: requiring all fields to be Set. however there is a workaround:

let test_station = stations_creston::ActiveModel {
    station_id: ActiveValue::Set(628),
    network_id: ActiveValue::Set("CRESNEKN".to_owned()),
    station_name: ActiveValue::Set("example".to_owned()),
    ..stations_creston::ActiveModel::default_values() // <- this would fill in Set(None) for installation_date
}
.try_into_model()
.expect("couldn't make test station model");
use sea_orm::DefaultActiveValueNone;

let v = (&ActiveValue::<Option<String>>::NotSet).default_value();
assert_eq!(v, ActiveValue::Set(None));

this will set the optional fields to None as you'd like.

may be we can change the behaviour of the conversion function, but I am thinking whether there'd be unintended consequences. I don't think converting NotSet to Set(None) should be the default implicit behaviour, but we can definitely add new APIs for that.

tyt2y3 avatar Dec 02 '25 09:12 tyt2y3

Thank you for the response! I think in this case all that is needed is a little more documentation to clarify. When I get a bit more time I want to look into contributing a derive macro for ergonomically making something like a NewMinimalModel that only takes the non-optional/non-nullable fields.

For now, I've made https://github.com/SeaQL/seaql.github.io/pull/160 to add the documentation.

p.s. I don't know if you assign issues to people in this project, but if you do feel free to assign me so I don't forget to come back to this in the next week or two!

PacificBird avatar Dec 02 '25 20:12 PacificBird