Rust使用Diesel操作PostgreSQL时查询模型列需与库表一致的原因及按需查询方案
为什么会出现列必须完全一致的编译错误
Diesel 的 Queryable trait 是基于字段位置做编译时类型匹配的,默认你直接用 playlist 表构造查询时,相当于执行 SELECT * FROM playlist,返回的字段顺序、数量、类型完全和你 table! 宏里定义的一致。如果你的结构体字段和查询返回的字段不匹配(少列、顺序错误、类型不对应),Diesel 就会在编译阶段抛出错误,本质是提前帮你避免运行时SQL字段不匹配的问题。
不需要每次查询所有列,完全支持按需查询指定列,操作方式如下:
方法1:查询时手动指定需要的列
在构造查询时调用 select 方法,传入你需要的字段,字段顺序要和 QueryPlaylist 结构体的字段顺序完全一致即可。修改你的查询代码如下:
#[get("/v1/playlist/detail/<req_playlist_id>")] pub fn playlist_detail(req_playlist_id: i64) -> content::Json<String> { use crate::schema::playlist::dsl::*; let connection = config::establish_connection(); let results = playlist // 按结构体字段顺序指定要查询的列,跳过不需要的source列 .select((id, creator, name, cover_url, description, subscribed, subscribed_count, comment_count, share_count, play_count)) .filter(id.eq(req_playlist_id)) .limit(1) .load::<QueryPlaylist>(&connection) .expect("Error loading playlist"); let response_json = serde_json::to_string(&results).unwrap(); return content::Json(response_json); }
方法2:按业务场景定义多个查询结构体
如果有多个不同的字段查询需求,可以定义多个不同的结构体,分别派生 Queryable 对应不同的字段组合,不需要所有查询都复用同一个结构体。比如你只需要查询歌单id和名称,可以单独定义:
#[derive(Serialize, Queryable)] #[table_name="playlist"] pub struct PlaylistBasicInfo { pub id: i64, pub name: String, }
查询时对应select这两个字段,load成 PlaylistBasicInfo 类型即可。
额外注意
你当前的 QueryPlaylist 派生了 Insertable,如果这个结构体只用于查询场景,建议去掉 Insertable 派生,单独定义插入场景用的结构体,避免插入时因为缺字段报错。如果需要保留插入功能,要确保插入时数据库 source 字段有默认值,或者结构体补充 source 字段。
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

