GORM many2many关系表的创建和查询

最近在用golang搭建个人博客的后台,数据库选用了gorm + mySQL的组合,其中文章(articles)和标签(tags)两个表是多对多的关系,由于对数据库不是很熟悉,外加gorm的文档较为简略,在这里踩了很多的坑。现在在这篇文章中总结下实现的方法。

第一步:定义gorm表的struct

type Article struct {
    gorm.Model
    Title     string            `gorm:"not null"`
    Content   string    `gorm:"not null"`
    Tags      []Tag     `gorm:"many2many:tag_articles"`
}

type Tag struct {
    TagId       string      `gorm:"primary_key"`
    TagName   string        `gorm:"unique;not null"`
    Articles  []Article     `gorm:"many2many:tag_articles"`
}

第二步:连接数据库,创建表

func InitDB() *gorm.DB {
    //创建一个数据库的连接
    var err error
    db, err := gorm.Open("mysql","root:071918@tcp(127.0.0.1:3306)/blog?charset=utf8")
    if err != nil {
        panic(err)
    }

    // 调用该语句会自动生成联结表tag_articles
    db.AutoMigrate(&Article{}, &Tag{})
    return db
}

第三步:存数据

tag1 := Tag{ TagId: "001", TagName: "React" }
db.Save(&tag1)
article := Article{
    Title: "Redux进阶教程", 
        Content:   "正文内容",
        // 子项中的数据必须是保存过或者查找出的数据(即数据库已有的数据)
        Tags: []Tag {
        tag1,
    },
}

或者

tagIdList := ["001", "002"]
var tags []db.Tag
// 分别查询tagIdList,并将结果插入tags列表
for i := range tagIdList {
    tag := db.Tag{}
    DB.Where("tag_id = ?", tagIdList[i]).First(&tag)
    tags = append(tags, tag)
}

articleModel := db.Article{
    Title:  "这是标题",
    Content:  "这是正文",
    Tags:      tags,
}
// 保存
err := DB.Save(&articleModel)

在上述步骤中有需要注意的是,Tags对应的数组项必须事先存入数据库,或者事先查找过,否则仅会生成article的记录,不会生成tag_articles联结表的记录。

第四步:查询

因为不熟悉gorm的API,有一部分查询是使用基本的sql语句查询的,性能方面可能不太好,但是作为个人博客后端使用问题不大。

查询带标签(Tag)子项的文章(Article)列表

var articleList []Article
err := DB.Preload("Tags").Find(&articleList)
fmt.Println(articleList)

查询带文章数(Count)的标签(Tag)列表

// 定义所需的struct
type tagResult struct {
    Count int
    TagName string
    TagId   string
}
var tagList []tagResult
err := DB.Raw("SELECT COUNT(*) count, t.tag_name, t.tag_id " +
    // 下面这句使用笛卡尔积连接两个表,复杂度变成了m * n,性能较差
    "FROM tag_articles ta, tags t " +
    "WHERE t.tag_id=ta.tag_tag_id " +
    "GROUP BY ta.tag_tag_id ").Scan(&tagList)
fmt.Println(tagList)

根据标签(TagId)查询全部文章列表

// 定义所需的struct
type articleResult struct {
    Title     string
    ArticleId string
}
var articleList []articleResult
tagId := "001"
// 查询语句
err := DB.Raw("SELECT a.title, a.article_id "+
        // 下面这句使用笛卡尔积连接两个表,复杂度变成了m * n,性能较差
    "FROM tag_articles ta, articles a "+
    "WHERE a.article_id=ta.article_article_id "+
    "AND ta.tag_tag_id= ? ", tagId).Scan(&articleList)
fmt.Println(articleList)

你可能感兴趣的:(GORM many2many关系表的创建和查询)