postgresql - 使用 Rust Diesel 插入记录时处理 ID 的最佳方法是什么

标签 postgresql rust rust-diesel

我正在使用 rustdiesel(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?这是我的表 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>,
}

还是没有解决。

最佳答案

插入时不添加 id Domain 中的字段值struct 我们可以通过用 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 Domain结构和 BigInt 也在内部 i64 我们告诉diesel反序列化id字段为 i64 #[diesel(deserialize_as = "i64")]而不是 BigInt 在获取时可以将其映射为 Option<i64>解决问题

关于postgresql - 使用 Rust Diesel 插入记录时处理 ID 的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70547237/

相关文章:

rust - 为什么在将使用 Diesel 的特征重写为特征方法的函数时得到 "overflow evaluating the requirement"?

postgresql - 不能使用 UUID 作为主键:Uuid:diesel::Expression 不满足

postgresql - Postgres 使用 LIMIT 1 选择性能

rust - cargo 未能为rustc_version选择版本

rust - 将柴油过滤器应用于单表还是连接表?

arrays - 从切片构建数组的正确方法?

rust - 为什么 `Box::new` 不返回 `Option` 或 `Result` ?

postgresql - flask SQLAlchemy : application crashed on postgres server reboot

javascript - 为 Postgresql tswtz 数据类型生成带有时区的服务器端时间戳

Python 字典 : Creating a prepared statement