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

如何在Rust中使用SQLX从关联表查询嵌套结构体?

解决Sqlx查询嵌套结构体的优雅方案

方案一:利用FromRow的字段前缀映射

Sqlx的FromRow支持通过属性指定字段的列前缀,可直接映射嵌套结构体,无需额外辅助结构体。

修改结构体定义

给PublicEvent的owner字段添加#[from_row(prefix = "owner_")]属性,让Sqlx自动匹配带前缀的查询列:

use sqlx::{FromRow, Postgres};
use uuid::Uuid;
use serde::Serialize;

#[derive(Debug, Serialize, FromRow)]
struct PublicUser {
    id: Uuid,
    username: String,
}

#[derive(Debug, Serialize, FromRow)]
struct PublicEvent {
    id: Uuid,
    name: String,
    #[from_row(prefix = "owner_")] // 指定嵌套字段的列前缀
    owner: PublicUser,
}

调整查询语句

查询时给User表的所有字段加上owner_前缀,与结构体属性对应:

use sqlx::{PgPool, query_as};
use anyhow::Result;

pub async fn list_events(pool: &PgPool) -> Result<Vec<PublicEvent>> {
    Ok(query_as(r#"
        SELECT 
            "Event".id, "Event".name,
            "User".id AS owner_id, "User".username AS owner_username
        FROM "Event"
        JOIN "User" ON "Event".owner_id = "User".id
    "#)
    .fetch_all(pool)
    .await?)
}

方案二:手动实现FromRow trait

如果需要更灵活的映射逻辑,可手动为PublicEvent实现FromRow,直接从PgRow中提取嵌套的PublicUser:

use sqlx::{FromRow, PgRow, Decode, Error as SqlxError};
use uuid::Uuid;
use serde::Serialize;

#[derive(Debug, Serialize, FromRow)]
struct PublicUser {
    id: Uuid,
    username: String,
}

#[derive(Debug, Serialize)]
struct PublicEvent {
    id: Uuid,
    name: String,
    owner: PublicUser,
}

impl<'r> FromRow<'r, PgRow> for PublicEvent {
    fn from_row(row: &'r PgRow) -> Result<Self, SqlxError> {
        Ok(Self {
            id: row.try_get("id")?,
            name: row.try_get("name")?,
            owner: PublicUser {
                id: row.try_get("user_id")?, // 对应查询中的字段别名
                username: row.try_get("username")?,
            },
        })
    }
}

// 对应手动实现的查询语句
pub async fn list_events(pool: &PgPool) -> Result<Vec<PublicEvent>, anyhow::Error> {
    Ok(query_as(r#"
        SELECT 
            "Event".id, "Event".name,
            "User".id AS user_id, "User".username
        FROM "Event"
        JOIN "User" ON "Event".owner_id = "User".id
    "#)
    .fetch_all(pool)
    .await?)
}

原代码报错原因

原代码中"User" as "owner: PublicUser"的写法无效,Sqlx无法将整行数据直接解码为自定义的PublicUser结构体——Decode trait没有实现这种批量解码逻辑,必须明确映射每个字段或使用前缀匹配规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 07:25:57