You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Diesel的get_result出现trait bound错误,求问题排查

Actix + Diesel 插入数据后无法返回结果问题

问题场景

基于Actix框架开发API并结合Diesel ORM,在实现/books/create端点时,插入数据后无法将结果返回至代码中。

插入代码

use diesel::prelude::*;
use crate::models::Book;
use crate::schema::books;
use crate::db;

pub fn create_book(book: &Book) -> Book {
    let mut connection: SqliteConnection = db::establish_connection();
    let result: QueryResult<Book> = diesel::insert_into(books::table)
        .values([book])
        .get_result::<Book>(&mut connection);
    
    result.unwrap()
}

错误说明

调用get_result时触发报错,核心矛盾在于SQLite的语法支持限制,同时Model设计存在逻辑冲突。

Model与Schema代码

Model定义

use diesel::prelude::*;
use serde::{Serialize, Deserialize};    
use crate::schema::books;

#[derive(Queryable, Serialize, Deserialize, Insertable)]
#[diesel(table_name = books)]
pub struct Book {
    pub id: i32,
    pub title: String,
    pub author: String,
    pub creation_date: Option<String>,
    pub publishing_house: Option<String>,
    pub release_date: Option<String>,
    pub cover_image: Option<String>
}

Schema定义

diesel::table! {
    books (id) {
        id -> Integer,
        title -> Text,
        author -> Text,
        publishing_house -> Nullable<Text>,
        release_date -> Nullable<Text>,
        cover_image -> Nullable<Text>,
        creation_date -> Nullable<Text>,
    }
}

问题分析与解决方法

错误原因

  • SQLite默认不支持RETURNING子句:Diesel的get_result方法依赖数据库的RETURNING语法返回插入后的完整记录,但SQLite 3.35.0版本才引入该特性,旧版本直接报错。
  • Insertable结构体包含自增ID:Book中的id是数据库自增主键,插入时传入该字段不符合自增逻辑,且会导致无法正确获取数据库生成的ID。

解决步骤

方案一:拆分Insertable结构体(推荐,兼容所有SQLite版本)

创建专门用于插入的NewBook结构体,不包含自增id字段,插入后通过last_insert_rowid获取ID再查询完整记录:

// models.rs
#[derive(Insertable)]
#[diesel(table_name = books)]
pub struct NewBook {
    pub title: String,
    pub author: String,
    pub creation_date: Option<String>,
    pub publishing_house: Option<String>,
    pub release_date: Option<String>,
    pub cover_image: Option<String>
}

// 插入函数修改为
pub fn create_book(new_book: &NewBook) -> Book {
    let mut connection = db::establish_connection();
    diesel::insert_into(books::table)
        .values(new_book)
        .execute(&mut connection)
        .unwrap();
    
    let last_id = connection.last_insert_rowid() as i32;
    books::table.find(last_id).get_result(&mut connection).unwrap()
}

方案二:启用SQLite RETURNING支持(需SQLite ≥3.35.0)

  1. 在Cargo.toml中添加Diesel的对应特性:
diesel = { version = "2.0", features = ["sqlite", "returning_clauses_for_sqlite_3_35"] }
  1. 修改Book结构体的Insertable属性,跳过id字段(插入时由数据库自动生成):
#[derive(Queryable, Serialize, Deserialize, Insertable)]
#[diesel(table_name = books)]
pub struct Book {
    #[diesel(skip)]
    pub id: i32,
    pub title: String,
    pub author: String,
    pub creation_date: Option<String>,
    pub publishing_house: Option<String>,
    pub release_date: Option<String>,
    pub cover_image: Option<String>
}
  1. 此时可继续使用get_result方法获取插入后的完整记录。

内容的提问来源于stack exchange,提问作者Zerok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 21:50:22