【问题标题】:Query a many-to-many relation using Gorm使用 Gorm 查询多对多关系
【发布时间】:2020-10-02 20:37:08
【问题描述】:

我有一个 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
}
  1. 如何从关系中查询带有 ID 的电影? (在我的例子中,查询所有 ID 为 1director 的电影。)
  2. 如何扩展它以查询具有多个 ID 和多个关系的电影? (例如,对于directors[3,4]types,查询所有具有[1,2] ID 的电影。)

【问题讨论】:

    标签: postgresql go go-gorm


    【解决方案1】:

    问题回复

    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 (?)
    

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

    以下可能解决方案的假设

    假设

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

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

    可能的解决方案 1

    Gorm 允许您使用raw-sql

    例如。

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

    可能的解决方案 2

    Gorm 允许您使用他们的query builder 构建自己的joins,如果您想优化在数据库上运行的查询,这可能会很有用。例如,如果您的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

    【讨论】:

    • 感谢您的解决方案。运行可能的解决方案 2 时出现错误,ERROR: syntax error at or near "$1" at character 138pq: syntax error at or near "$1"
    • 它创建了这个查询:STATEMENT: SELECT movies.* FROM "movies" LEFT JOIN movie_categories on movie_categories.movie_id = movies.id WHERE (movie_categories.category_id IN $1)
    • @Morteza 我已经对其进行了修改,将query = query.Where("movie_categories.category_id IN (?)",categories); 包含在括号中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-20
    • 2017-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-31
    相关资源
    最近更新 更多