使用 Gorm 查询多对多关系

Mor*_*eza 1 postgresql go go-gorm

我有一个Movie模型,它在 Gorm 中定义了很多多对多关系。现在我必须创建一个 API 来查询在这些关系中具有 ID 的所有电影。

让我们把它分成小块:

电影型号:

type Movie struct {
    gorm.Model
    TitleID           string     `gorm:"size:50;not null" json:"title_id"`
    OriginalName      string     `gorm:"size:250;not null" json:"original_name"`
    Categories        []Category `gorm:"null;many2many:movie_categories;" json:"categories"`
    Types             []Type     `gorm:"null;many2many:movie_types;" json:"types"`
    Directors         []Cast     `gorm:"null;many2many:movie_directors;" json:"directors"`
    Writers           []Cast     `gorm:"null;many2many:movie_writers;" json:"writers"`
}
Run Code Online (Sandbox Code Playgroud)

我的查询功能:

func (u *Movie) FindMoviesByDirectors(db *gorm.DB, directors string) (*[]Movie, error) {
    var err error
    movies := []Movie{}
    err = db.Set("gorm:auto_preload", true).Where("directors = ?", directors).Find(&movies).Error
    if err != nil {
        return &[]Movie{}, err
    }
    return &movies, err
}
Run Code Online (Sandbox Code Playgroud)
  1. 如何通过关系中的 ID 查询电影?1(在我的例子中,查询所有 ID 为的电影director。)
  2. 如何扩展它来查询具有多个 ID 和多个关系的电影?(例如,查询[1,2]ID 为directors[3,4]的所有电影types。)

ggo*_*don 6

问题答复

  1. 您可以查询引用的多对多关系中的外键引用 id(参见下面的示例)
  2. 您可以使用IN运算符一次查询多个值。gorm支持这一点,请参阅https://gorm.io/docs/query.html

可能的解决方案

为此,您的原始 sql 可能如下所示:

SELECT 
    M.* 
FROM
    movies M
LEFT JOIN movie_categories MC on MC.movie_id = M.id
LEFT JOIN movie_types MT on MT.movie_id = M.id
LEFT JOIN movie_directors MD on MD.movie_id = M.id
LEFT JOIN movie_writers MW on MW.movie_id = M.id
WHERE
  MC.category_id IN (?) OR
  MT.type_id IN (?) OR
  MD.director_id IN (?) OR
  MW.writer_id IN (?)
Run Code Online (Sandbox Code Playgroud)

注意。如果电影在特定关系中没有记录,我会使用左连接。where 条件将确保返回所需的记录。此外,这OR意味着可以满足这些标准中的任何一个。如果您希望满足所有这些标准,您可以使用AND代替OR

以下可能解决方案的假设

假如说

  1. 上面的sql存储在变量中sql
  2. 所需的类别 id 存储在数组中,categories例如。[]int64{1,2,3}
  3. 所需的类型 id 存储在数组中,types例如。[]int64{1,2,3}
  4. 所需的导演 ID 存储在数组中,directors例如。[]int64{1,2,3}
  5. 所需的作者 ID 存储在数组中,writers例如。[]int64{1,2,3}

您可以根据需要修改函数签名以根据需要接受这些参数。

可能的解决方案1

Gorm允许您使用raw-sql

例如。


result := db.Raw(sql,categories,types,directors,writers).Scan(&movies)
err := result.Error

Run Code Online (Sandbox Code Playgroud)

可能的解决方案2

Gormjoins允许您使用他们的查询构建器构建自己的查询构建器,如果您想优化在数据库上运行的查询,这可能会很有用。例如,如果您的directors数组为空但categories不是空的,则只能查询categories关系。此外,您可以使用构建器对象微调查询

例如。


var query = db.Table("movies") //or you could use db.Model(&Movie{})

query = query.Select("movies.*")

// begin querying relations
if( len(categories)>0 ){
    query = query.Joins("LEFT JOIN movie_categories on movie_categories.movie_id = movies.id");
}

if( len(categories)>0 ){
    query = query.Where("movie_categories.category_id IN (?)",categories);
}
//end querying relations
//you could repeat this for each relation

//With the Gorm query builder object store in query you can make other modifications before executing the query

result := query.Scan(&movies)
err := result.Error

Run Code Online (Sandbox Code Playgroud)

其他注意事项

如果您有兴趣根据类别名称查询所有电影,您可以使用相同的方法来joins编写查询。

参考资料/资源

Gorm Where In- https://gorm.io/docs/query.html

Gorm SQL 生成器 - https://gorm.io/docs/sql_builder.html