【问题标题】:Understanding trait bound error in Diesel了解 Diesel 中的特征绑定错误
【发布时间】:2018-05-02 17:17:52
【问题描述】:

我想编写一个函数,将一个类型插入到数据库连接参数是通用的数据库中,以便它可以在多个后端工作。

我想出了以下函数来使用通用连接插入对象:

pub fn create_label<C>(connection: &C, label: &model::Label)
where
    C: Connection,
    C::Backend: diesel::backend::Backend,
    C::Backend: diesel::backend::SupportsDefaultKeyword,
{
    diesel::insert(&label)
        .into(schema::label::table)
        .execute(connection);
}

如果我不包含SupportsDefaultKeyword 约束,该函数将无法编译。使用SqliteConnection 作为连接参数调用它时,出现以下错误:

database::create_label(&db_conn, &label); ^^^^^^^^^^^^^^^^^^^^^^ the trait 'diesel::backend::SupportsDefaultKeyword' is not implemented for 'diesel::sqlite::Sqlite'

这意味着使用SqliteConnection 插入数据不起作用。显然情况并非如此,此外,将create_label 更改为直接使用SqliteConnection 就可以了。

pub fn create_label(connection: &SqliteConnection, label: &model::Label) {
    diesel::insert(&label)
        .into(schema::label::table)
        .execute(connection);
}

为什么泛型函数需要SupportsDefaultKeyword 约束而使用SqliteConnection 的函数不需要?

这是一个minimal example 说明问题。根据 cmets,main.rs 的第 60 行不会编译并出现上面的错误,而第 61 行会编译:

#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_codegen;

mod schema {
    table! {
        labels {
            id -> Integer,
            name -> VarChar,
        }
    }
}

mod model {
    use schema::labels;

    #[derive(Debug, Identifiable, Insertable)]
    #[table_name = "labels"]
    pub struct Label {
        pub id: i32,
        pub name: String,
    }
}

use diesel::ExecuteDsl;
use diesel::Connection;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;

pub fn create_label<C>(connection: &C, label: &model::Label)
where
    C: Connection,
    C::Backend: diesel::backend::Backend,
    C::Backend: diesel::backend::SupportsDefaultKeyword,
{
    diesel::insert(label)
        .into(schema::labels::table)
        .execute(connection)
        .expect("nope");
}

pub fn create_label_sqlite(connection: &SqliteConnection, label: &model::Label) {
    diesel::insert(label)
        .into(schema::labels::table)
        .execute(connection)
        .expect("nope");
}

pub fn establish_connection() -> SqliteConnection {
    let url = "test.db";
    SqliteConnection::establish(&url).expect(&format!("Error connecting to {}", url))
}

fn main() {
    let label = model::Label {
        id: 1,
        name: String::from("test"),
    };
    let conn = establish_connection();

    create_label(&conn, &label); /* Does not compile */
    create_label_sqlite(&conn, &label); /*Compiles */
}
[dependencies]
diesel = { version = "0.16.0", features = ["sqlite"] }
diesel_codegen = "0.16.0"

【问题讨论】:

    标签: rust rust-diesel


    【解决方案1】:

    Diesel 函数execute 有多个具体实现。这里相关的两个是:

    impl<'a, T, U, Op, Ret, Conn, DB> ExecuteDsl<Conn, DB> for BatchInsertStatement<T, &'a [U], Op, Ret> 
    where
        Conn: Connection<Backend = DB>,
        DB: Backend + SupportsDefaultKeyword,
        InsertStatement<T, &'a [U], Op, Ret>: ExecuteDsl<Conn>, 
    
    impl<'a, T, U, Op, Ret> ExecuteDsl<SqliteConnection> for BatchInsertStatement<T, &'a [U], Op, Ret> 
    where
        InsertStatement<T, &'a U, Op, Ret>: ExecuteDsl<SqliteConnection>,
        T: Copy,
        Op: Copy,
        Ret: Copy, 
    

    从这两个可以看出,SQLite 的实现是特殊的。我对 Diesel 的详细信息知之甚少,不知道为什么,但我猜 SQLite 缺少默认关键字。

    您可以改为重新制定适用于该特定语句的任何连接的要求:

    use diesel::query_builder::insert_statement::InsertStatement;
    
    pub fn create_label<C>(connection: &C, label: &model::Label)
    where
        C: Connection,
        for<'a> InsertStatement<schema::labels::table, &'a model::Label>: ExecuteDsl<C>,
    {
        diesel::insert(label)
            .into(schema::labels::table)
            .execute(connection)
            .expect("nope");
    }
    

    【讨论】:

      猜你喜欢
      • 2021-03-30
      • 2023-04-04
      • 1970-01-01
      • 2012-01-17
      • 1970-01-01
      • 2021-04-25
      • 1970-01-01
      • 1970-01-01
      • 2019-09-10
      相关资源
      最近更新 更多