首页 > 解决方案 > 急切加载关系

问题描述

我有三个具有这些关系的模型:

艺术家 1<->n 歌曲 1<->n 播放

我想加载 Plays 并急切地加载它的歌曲和艺术家。

我很容易在 PHP 框架 Eloquent 中做到了这一点。它只需要 3 个数据库请求(每个模型一个)。

这对柴油来说有可能吗?

我认为 Play 模型应该是这样的:

#[derive(Queryable, Serialize, Deserialize)]
pub struct Play {
    pub id: u64,
    pub song_id: u64,
    pub song: Song, // <-- ????
    pub date: NaiveDateTime,
    pub station_id: u64,
}

并加载这样的内容:

// loads one model only at the moment
// it should load the related models Song and Artist too
let items = plays.filter(date.between(date_from, date_to)).load(&*conn)?;

生成的结构应为 JSON 序列化以供 REST API 使用。但是我找不到以一种简单有效的方式获得所需结构的方法。

标签: rustormeager-loadingrust-diesel

解决方案


实现此目的的一种方法是连接另外两个表。不幸的是,我没有弄清楚如何避免枚举所有表字段。这不是一个优雅的解决方案,但它应该可以工作。

fn select_plays_with_song_and_artist(
    conn: &Conn,
    date_from: NaiveDate,
    date_to: NaiveDate,
) -> Result<Vec<(models::Play, models::Song, models::Artist)>> {
    plays::table                
    .filter(plays::date.between(date_from, date_to))               
    .join(songs::table.join(artists::table))                                             
    .select((                                                               
        (
            plays::id,  
            plays::song_id,     
            plays::date,     
            plays::station_id,                                      
        ),
        (
            songs::id,
            // other relevant fields...
        ),
        (
            artist::id,
            // other relevant fields...
        ),
     ))                                                                           
     .load::<(models::Play, models::Song, models::Artist)>(conn)
}

推荐阅读