在正式开始之前,我们需要再次对数据库进行设置,不过跟上次只创建一个表的做法不同,这一次我们将会创建两个表。此外,这次设置需要用到的命令跟上一次设置使用的命令完全一样,只是被执行的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)//③
}

results matching ""

    No results matching ""