在正式开始之前,我们需要再次对数据库进行设置,不过跟上次只创建一个表的做法不同,这一次我们将会创建两个表。此外,这次设置需要用到的命令跟上一次设置使用的命令完全一样,只是被执行的setup.sql
脚本跟之前的有所不同,代码清单6-13展示了新脚本的具体定义。
代码清单6-13 创建两个相关联的表
drop table posts cascade if exists;
drop table comments if exists;
create table posts (
id serial primary key,
content text,
author varchar(255)
);
create table comments (
id serial primary key,
content text,
author varchar(255),
post_id integer references posts(id)
);
这次的脚本除了会创建posts
表之外,还会创建comments
表,comments
表的大部分列都跟posts
表一样,主要区别在于comments
表多了一个额外的post_id
列:这个post_id
会作为外键(foreign key),对posts
表的主键id
进行引用。此外,因为posts
表和comments
表现在已经通过主键和外键建立起了关联,所以用户在删除posts
表的同时也需要将comments
表一并删除;否则,由于comments
表对posts
表的依赖关系,删除posts
表这一操作将无法正常执行。
设置好相应的数据库表之后,现在让我们来看看如何使用Go语言实现一对多以及多对一关系。代码清单6-14展示了具体的实现代码,这些代码都存储在一个名为store.go
的文件里面。
代码清单6-14 使用Go语言实现一对多以及多对一关系
package main
import (
"database/sql"
"errors"
"fmt"
_ "github.com/lib/pq"
)
type Post struct {
Id int
Content string
Author string
Comments []Comment
}
type Comment struct {
Id int
Content string
Author string
Post *Post
}
var Db *sql.DB
func init() {
var err error
Db, err = sql.Open("postgres", "user=gwp dbname=gwp password=gwp sslmode=disable")
if err != nil {
panic(err)
}
}
func (comment *Comment) Create() (err error) {//①创建一条评论
if comment.Post == nil {
err = errors.New("Post not found")
return
}
err = Db.QueryRow("insert into comments (content, author, post_id) values ($1, $2, $3) returning id",
comment.Content, comment.Author, comment.Post.Id).Scan(&comment.Id)
return
}
func GetPost(id int) (post Post, err error) {
post = Post{}
post.Comments = []Comment{}
err = Db.QueryRow("select id, content, author from posts where id = $1", id)
.Scan(&post.Id, &post.Content, &post.Author)
rows, err := Db.Query("select id, content, author from comments where post_id = $1", id)
if err != nil {
return
}
for rows.Next() {
comment := Comment{Post: &post}
err = rows.Scan(&comment.Id, &comment.Content, &comment.Author)
if err != nil {
return
}
post.Comments = append(post.Comments, comment)
}
rows.Close()
return
}
func (post *Post) Create() (err error) {
err = Db.QueryRow("insert into posts (content, author) values ($1, $2) returning id",
post.Content, post.Author).Scan(&post.Id)
return
}
func main() {
post := Post{Content: "Hello World!", Author: "Sau Sheong"}
post.Create()
comment := Comment{Content: "Good post!", Author: "Joe", Post: &post}
comment.Create()
readPost, _ := GetPost(post.Id)//②
fmt.Println(readPost)
fmt.Println(readPost.Comments)
fmt.Println(readPost.Comments[0].Post)//③
}