使用 rust diesel 插入记录时处理 id 的最佳方法是什么

what is the best way to handle the id when insert record using rust diesel

我正在使用 rust diesel(diesel = { version = "1.4.7", features = ["postgres","64-column-tables","chrono"] }) 向 PostgreSQL 13 中插入​​一条记录,这是我的 rust 代码:

pub fn add_domain(request: &Json<AddDomainRequest>, login_user_info: LoginUserInfo) {
    let connection = config::establish_connection();
    let timestamp: i64 = get_current_millisecond();
    let new_domain = Domain {
        id: 0,
        domain_name: request.domainName.to_string(),
        domain_url: request.domainUrl.to_string(),
        created_time: timestamp,
        updated_time: timestamp,
        cron: Some("* */1 * * * *".parse().unwrap()),
        next_trigger_time: None,
        monitor_status: None,
        user_id: Option::from(login_user_info.userId),
        expire_date: None,
        days_before_trigger: 7,
        notify_trigger_date: None,
        expire_date_ms: None,
    };
    diesel::insert_into(crate::model::diesel::dolphin::dolphin_schema::domain::table)
        .values(&new_domain)
        .on_conflict_do_nothing()
        .execute(&connection)
        .unwrap();
}

我不知道如何处理主键id,域模型是自动生成的(意味着我不能修改域,因为它会覆盖下一次自动生成的修改),如果我删除id ,我无法新建域,如果我保留 id,PostgreSQL 数据库将显示此错误:

thread 'rocket-worker-thread' panicked at 'called `Result::unwrap()` on an `Err` value: DatabaseError(__Unknown, "cannot insert into column \"id\"")', src/service/app/cernitor/domain/domain_service.rs:46:10
   >> Handler add panicked.
   >> This is an application bug.
   >> A panic in Rust must be treated as an exceptional event.
   >> Panicking is not a suitable error handling mechanism.
   >> Unwinding, the result of a panic, is an expensive operation.
   >> Panics will severely degrade application performance.
   >> Instead of panicking, return `Option` and/or `Result`.
   >> Values of either type can be returned directly from handlers.
   >> A panic is treated as an internal server error.
   >> Outcome: Failure
   >> No 500 catcher registered. Using Rocket default.
   >> Response succeeded.

我应该怎么做才能让柴油机忽略自动生成的 ID?这是我的 table DDL:

CREATE TABLE public."domain" (
    id int8 NOT NULL GENERATED ALWAYS AS IDENTITY,
    domain_name varchar NOT NULL,
    domain_url varchar NOT NULL,
    created_time int8 NOT NULL,
    updated_time int8 NOT NULL,
    cron varchar NULL,
    next_trigger_time timestamp(0) NULL,
    monitor_status varchar NULL DEFAULT 1,
    user_id int8 NULL,
    expire_date timestamp NULL,
    days_before_trigger int4 NOT NULL DEFAULT 14,
    notify_trigger_date timestamp NULL GENERATED ALWAYS AS (expire_date - make_interval(days => days_before_trigger)) STORED,
    expire_date_ms int8 NULL,
    CONSTRAINT domain_record_pk PRIMARY KEY (id)
);

我试着像这样调整实体:

#[derive(Insertable,Queryable,Debug,Serialize,Deserialize,Default,Identifiable)]
#[primary_key(id)]
#[table_name = "domain"]
pub struct Domain {
    pub id: i64,
    pub domain_name: String,
    pub domain_url: String,
    pub created_time: i64,
    pub updated_time: i64,
    pub cron: Option<String>,
    pub next_trigger_time: Option<NaiveDateTime>,
    pub monitor_status: Option<String>,
    pub user_id: Option<i64>,
    pub expire_date: Option<NaiveDateTime>,
    pub days_before_trigger: i32,
    pub notify_trigger_date: Option<NaiveDateTime>,
    pub expire_date_ms: Option<i64>,
}

还是没修好

要插入而不在 Domain 结构中添加 id 字段值,我们可以通过用 Option 类型

包装它来使 id 字段可选
#[derive(Default,Debug,Queryable,Identifiable,Insertable,Serialize,Deserialize)]
#[diesel(primary_key(id))]
#[table_name = "domain"]
pub struct Domain {
    #[diesel(deserialize_as = "i64")]
    pub id: Option<i64>,
    pub domain_name: String,
    pub domain_url: String,
    pub created_time: i64,
    pub updated_time: i64,
    pub cron: Option<String>,
    pub next_trigger_time: Option<NaiveDateTime>,
    pub monitor_status: Option<String>,
    pub user_id: Option<i64>,
    pub expire_date: Option<NaiveDateTime>,
    pub days_before_trigger: i32,
    pub notify_trigger_date: Option<NaiveDateTime>,
    pub expire_date_ms: Option<i64>,
}

然后在创建 Domain 实例时,我们可以将 None 作为值传递给 id 字段。

注:

#[diesel(deserialize_as = "i64")]

的解释

在使用 get_results 获取结果时,我们会遇到以下问题:

error[E0277]: the trait bound `Option<i64>: Queryable<BigInt, Pg>` is not satisfied
  --> src/lib.rs:58:10
   |
58 |         .get_result(conn)
   |          ^^^^^^^^^^ the trait `Queryable<BigInt, Pg>` is not implemented for `Option<i64>`
   |

该错误与 id 字段反序列化有关,其中指出 BigInt 无法直接反序列化为 Option<i64>

因为 id 字段在提取时是 i64 in Domain struct and BigInt is also internally i64 we told diesel to deserialize id field as i64 with #[diesel(deserialize_as = "i64")] instead of BigInt 然后可以映射为 Option<i64> 来解决问题