使用 sqlx 和 rust 将结构插入 sqlite 数据库

Rub*_*ubo 3 sqlite rust rust-rocket rust-sqlx

我有一个关于将数据结构插入数据库的问题,但我似乎找不到任何相关文档。

我有一个数据结构

#[derive(FromRow, Getters, Default, Serialize, Deserialize, Debug)]
#[serde(crate = "rocket::serde")]
#[getset(get = "pub")]
pub struct RefreshKeys {
    id: i64,
    customer_id: i64,
    key: String,
    enabled: bool,
}
Run Code Online (Sandbox Code Playgroud)

我想将其插入到具有相同字段的数据库中,称为refresh_keys.

rocket_db_pools::sqlx::query_as::<_, RefreshKeys>(
  "INSERT INTO refresh_keys (id, customer_id, key, enabled)
   VALUES (?1, ?2, ?3, ?4)"
)
.fetch_one(&mut *db)
.await?
Run Code Online (Sandbox Code Playgroud)

遗憾的是,这似乎不起作用,我收到以下错误:

SqliteError { code: 1299, message: "NOT NULL constraint failed: refresh_keys.customer_id" }
Run Code Online (Sandbox Code Playgroud)

我已经尝试了几个小时来查找相关文档,但我什么也没找到。

提前致谢!

小智 5

您看到的错误消息似乎表明与参数关联的数据未正确传递 ( ?1...?4),因为这会导致值作为 NULL 传递。

  • 由于对 SQLite 不太熟悉,我的第一个想法是你的参数应该被命名$1..$N,但看起来 SQLite 确实允许?NNN使用文档中的语法。那么让我们继续...

接下来尝试仔细查看需要将值绑定到参数的查询;我没有看到您将值传递给查询的位置,例如,我们可以创建一行数据并将其插入数据库,如下所示。请注意bind()将变量的值绑定data到查询中的参数的调用。

// Create new row to insert:
    let data = RefreshKeys {
        id: 1,
        customer_id: 1,
        key: "test".to_string(),
        enabled: true,
    };
// Now insert the row:
    let result = sqlx::query(
        "INSERT INTO refresh_keys (id, customer_id, key, enabled)
        VALUES ($1, $2, $3, $4)")
        .bind(data.id)
        .bind(data.customer_id)
        .bind(data.key)
        .bind(data.enabled)
        .execute(&pool).await;
Run Code Online (Sandbox Code Playgroud)

如果没有最小的工作示例,就很难进一步帮助您,但看看下面的示例是否有帮助。

工作最小示例

货物.toml:

[dependencies]
sqlx = { version = "0.6.3", features = ["sqlite", "macros", "runtime-tokio-rustls"] }
tokio = { version = "1.27.0", features = ["macros"] }
Run Code Online (Sandbox Code Playgroud)

src/main.rs:

use sqlx::{Sqlite, SqlitePool, migrate::MigrateDatabase};

#[derive(sqlx::FromRow)]
struct RefreshKeys {
    id: i32,
    customer_id: i64,
    key: String,
    enabled: bool,
}

const DATABASE_URL: &str = "sqlite://db.sqlite";

#[tokio::main]
async fn main() {

    // Create database if not exists:
    if !Sqlite::database_exists(DATABASE_URL).await.unwrap_or(false) {
        match Sqlite::create_database(DATABASE_URL).await {
            Ok(_) => println!("Database created"),
            Err(e) => println!("Error creating database: {}", e),
        }
    } else {
        println!("Database already exists");
    }

    // Connect to database:
    let pool = SqlitePool::connect(DATABASE_URL).await.unwrap();

    // Create table (would normally do this in ./migrations/*.sql):
    let result = sqlx::query("CREATE TABLE IF NOT EXISTS refresh_keys (
        id INTEGER PRIMARY KEY,
        customer_id INTEGER NOT NULL,
        key TEXT NOT NULL,
        enabled BOOLEAN NOT NULL
    )").execute(&pool).await;

    match result {
        Ok(_) => println!("Table created"),
        Err(e) => println!("Error creating table: {}", e),
    }

    // Create new row to insert:
    let data = RefreshKeys {
        id: 1,
        customer_id: 1,
        key: "test".to_string(),
        enabled: true,
    };

    let result = sqlx::query(
        "INSERT INTO refresh_keys (id, customer_id, key, enabled)
        VALUES ($1, $2, $3, $4)")
        .bind(data.id)
        .bind(data.customer_id)
        .bind(data.key)
        .bind(data.enabled)
        .execute(&pool).await;

    match result {
        Ok(_) => println!("Row inserted"),
        Err(e) => println!("Error inserting row: {}", e),
    }

    // Select row in database:
    let keys = sqlx::query_as::<_, RefreshKeys>(
        "SELECT * FROM refresh_keys"
        ).fetch_all(&pool).await;

    let key_vec = match keys {
        Ok(keys) => keys,
        Err(e) => {
            println!("Error selecting row: {}", e);
            return;
        }
    };

    for key in key_vec {
        println!("id={}, customer_id={}, key={}, enabled={}",
                 key.id,
                 key.customer_id,
                 key.key,
                 key.enabled);
    }

}
:q
Run Code Online (Sandbox Code Playgroud)