Rust Diesel Abstract 更新函数

Posted

技术标签:

【中文标题】Rust Diesel Abstract 更新函数【英文标题】:Rust Diesel Abstract update function 【发布时间】:2021-12-24 13:45:58 【问题描述】:

我目前正在尝试实现抽象函数,该函数将为数据库中的任何表更新一些元字段,但遇到了 Identifiable 问题。

我有一个数据库,其中每个表都有元字段:

....
pub updu: Option<Uuid>, // ID of a user who changed it 
pub updt: Option<NaiveDateTime>, //updated with current date/time on every change
pub ver: Option<i32>, //Version increases on every change
.....

我想实现一个对每个实体进行更新的函数。目前我有这个实现:

pub fn update<Model>(
    conn: &PgConnection,
    old_model: Model,
    mut updated_model: Model,
    user_id: Uuid,
) -> Result<Model, diesel::result::Error>
where
    Model: MetaFields + AsChangeset<Target = <Model as HasTable>::Table> + IntoUpdateTarget,
    Update<Model, Model>: LoadQuery<PgConnection, Model>

    updated_model.update_fields(user_id);
    Ok(
        diesel::update(old_model)
            .set(updated_model)
            .get_result(conn).unwrap()
    )

当我尝试调用它时,它会显示此错误:

error[E0277]: the trait bound `Marking: Identifiable` is not satisfied
   --> src/service/marking_service.rs:116:24
    |
116 |     web::block(move || common::dao::update(&conn2, real_marking1[0].clone(), marking2_to_update, jwt_token.user_id))
    |                        ^^^^^^^^^^^^^^^^^^^ the trait `Identifiable` is not implemented for `Marking`
    |
    = help: the following implementations were found:
              <&'ident Marking as Identifiable>
    = note: required because of the requirements on the impl of `IntoUpdateTarget` for `Marking`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `testapi` due to previous error

我在本例中尝试更新的实体是:

use chrono::NaiveDateTime, Utc;
use common::model::MetaFields;
use common::utils::constants::DEL_MARK_AVAILABLE;
use serde::Deserialize, Serialize;
use serde_json;
use uuid::Uuid;

use crate::schema::marking;

#[derive(
    Clone,
    Serialize,
    Deserialize,
    Debug,
    Queryable,
    Insertable,
    AsChangeset,
    Identifiable,
    QueryableByName,
    Default,
)]
#[primary_key(uuid)]
#[table_name = "marking"]
pub struct Marking 
    pub uuid: Uuid,
    pub updt: Option<NaiveDateTime>,
    pub ver: Option<i32>,
    pub updu: Option<Uuid>,
    pub comment: Option<String>,
    pub status: Option<String>,


impl MetaFields for Marking 
    fn update_fields(&mut self, user_id: Uuid) 
        self.updu = Option::from(user_id);
        self.ver = Option::from(self.ver.unwrap() + 1);
        self.updt = Option::from(Utc::now().naive_local());
    

如您所见,为该实体定义了 Identifiable,但由于某种原因更新无法看到它。有人可以建议我在这里缺少什么吗? 更新,架构:

table! 
    marking (uuid) 
        uuid -> Uuid,
        updt -> Nullable<Timestamp>,
        ver -> Nullable<Int4>,
        updu -> Nullable<Uuid>,
        comment -> Nullable<Varchar>,
        status -> Nullable<Varchar>,
    

diesel =  version = "1.4.6", features = ["postgres", "uuid", "chrono", "uuidv07", "serde_json"] 
r2d2 = "0.8"
r2d2-diesel = "1.0.0"
diesel_json = "0.1.0"

【问题讨论】:

【参考方案1】:

您的代码几乎是正确的。错误消息已经提到了这个问题:

#[derive(Identifiable)] 确实生成了以下 impl:impl&lt;'a&gt; Identifiable for &amp;'a struct ,这意味着 trait 仅用于对 self 的引用。根据您的其他特征设置,您可以尝试以下操作:

将引用传递为old_model common::dao::update 更改common::dao::update 的定义以将引用作为第二个参数。然后,您可以将 Model 的特征边界分开,以便将 IntoUpdateTarget 绑定在 &amp;Model 上。

(很难猜测哪个会是更好的解决方案,因为您的问题缺少很多重要的上下文。请尝试在未来提供一个完整的最小示例。)

【讨论】:

感谢您的回复!这几乎是完整的示例,我添加了一些我认为没有必要的细节。我希望这就足够了。如果还有其他有用的信息,请提出建议。 @Dmitrii 我不确定在这里还能说什么。这与您的问题中缺少信息无关,而只是#[derive(Identifiable)] 生成了impl&lt;'a&gt; Identifable for &amp;'a YourType ,这意味着它不是针对类型本身实现的,而仅针对类型的引用。这意味着您的代码可能永远不会以这种方式工作,至少在不更改更新函数的情况下不会。

以上是关于Rust Diesel Abstract 更新函数的主要内容,如果未能解决你的问题,请参考以下文章

Rust Diesel 无法编译并出现链接器错误

返回使用 Rocket 和 Diesel (Rust) 在 PostgreSQL 中创建的单个记录

使用 r2d2 在 rust/diesel 应用程序中实现连接池

Rust Diesel 未构建错误使用未声明的板条箱或模块

Rust Diesel 原始 SQL 给出错误“`std::result::Result<Vec<T>,diesel::result::Error>` 所需的类型注释”

Rust Diesel:特征绑定 `NaiveDateTime: Deserialize<'_>` 不满足