使用 Gorm 查询多对多关系
Query a many-to-many relation using 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"`
}
我的查询函数:
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
}
- 如何从关系中查询具有 ID 的电影? (在我的例子中,查询所有 ID
1
为 director
的电影。)
- 如何扩展它来查询具有多个ID和多个关系的电影? (例如,查询所有具有
[1,2]
ID 的电影 directors
和 [3,4]
的 types
。)
问题回复
- 您可以在引用的 many-to-many 关系中查询外键引用 ID(参见下面的示例)
- 您可以使用
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 (?)
注意。如果电影在特定关系中没有记录,我会使用 Left join。 where 条件将确保返回所需的记录。此外,OR
意味着可以满足这些条件中的任何一个。如果您希望满足所有这些条件,您可以使用 AND
而不是 OR
。
以下可能解决方案的假设
假设
- 上面的sql存储在变量
sql
中
- 存储在数组中的所需类别 ID
categories
例如。 []int64{1,2,3}
- 存储在数组中的所需类型 ID
types
例如。 []int64{1,2,3}
- 所需的导演 ID 存储在数组中
directors
例如。 []int64{1,2,3}
- 所需的作者 ID 存储在数组中
writers
例如。 []int64{1,2,3}
您可以根据需要修改您的函数签名以根据需要接受这些参数。
可能的解决方案 1
Gorm
允许您使用 raw-sql
例如
result := db.Raw(sql,categories,types,directors,writers).Scan(&movies)
err := result.Error
可能的解决方案 2
Gorm
允许您构建自己的 joins
using their query builder 如果您想优化数据库上的查询 运行 这可能很有用。例如,如果您的 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
其他注意事项
如果您有兴趣根据类别名称查询所有电影,您可以使用与 joins
相同的方法来编写查询。
参考资料/资源
戈尔姆 Where In
- https://gorm.io/docs/query.html
Gorm SQL 生成器 - https://gorm.io/docs/sql_builder.html
我有一个 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"`
}
我的查询函数:
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
}
- 如何从关系中查询具有 ID 的电影? (在我的例子中,查询所有 ID
1
为director
的电影。) - 如何扩展它来查询具有多个ID和多个关系的电影? (例如,查询所有具有
[1,2]
ID 的电影directors
和[3,4]
的types
。)
问题回复
- 您可以在引用的 many-to-many 关系中查询外键引用 ID(参见下面的示例)
- 您可以使用
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 (?)
注意。如果电影在特定关系中没有记录,我会使用 Left join。 where 条件将确保返回所需的记录。此外,OR
意味着可以满足这些条件中的任何一个。如果您希望满足所有这些条件,您可以使用 AND
而不是 OR
。
以下可能解决方案的假设
假设
- 上面的sql存储在变量
sql
中
- 存储在数组中的所需类别 ID
categories
例如。[]int64{1,2,3}
- 存储在数组中的所需类型 ID
types
例如。[]int64{1,2,3}
- 所需的导演 ID 存储在数组中
directors
例如。[]int64{1,2,3}
- 所需的作者 ID 存储在数组中
writers
例如。[]int64{1,2,3}
您可以根据需要修改您的函数签名以根据需要接受这些参数。
可能的解决方案 1
Gorm
允许您使用 raw-sql
例如
result := db.Raw(sql,categories,types,directors,writers).Scan(&movies)
err := result.Error
可能的解决方案 2
Gorm
允许您构建自己的 joins
using their query builder 如果您想优化数据库上的查询 运行 这可能很有用。例如,如果您的 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
其他注意事项
如果您有兴趣根据类别名称查询所有电影,您可以使用与 joins
相同的方法来编写查询。
参考资料/资源
戈尔姆 Where In
- https://gorm.io/docs/query.html
Gorm SQL 生成器 - https://gorm.io/docs/sql_builder.html