go-pg如何从相关表中选择实体?

huangapple go评论120阅读模式
英文:

go-pg how to select also entity from related table?

问题

  1. 类型 Book 结构体 {
  2. tableName struct{} `pg:"book" json:"-"`
  3. Id int `pg:"id,pk" json:"id"`
  4. Author int `pg:"author_id,notnull" json:"-"`
  5. Author *Author `pg:"fk:author_id" json:"author,omitempty"`
  6. }

我想在一次查询中选择书籍和作者。

如果我尝试这样做:

  1. var r []model.Book
  2. _, err := dao.FusedDb.Query(&r, `SELECT * FROM book b INNER JOIN author a on a.id = b.author_id`)

我会得到一个错误

pg: can't find column=name in model=Book (try discard_unknown_columns)

  1. <details>
  2. <summary>英文:</summary>

type Book struct {
tableName struct{} pg:&quot;book&quot; json:&quot;-&quot;
Id int pg:&quot;id,pk&quot; json:&quot;id&quot;
Author int pg:&quot;author_id,notnull&quot; json:&quot;-&quot;
Author *Author pg:&quot;fk:author_id&quot; json:&quot;author,omitempty&quot;
}

  1. I want select book and author in one query.
  2. If I try this:

var r []model.Book
_, err := dao.FusedDb.Query(&r, SELECT * FROM book b INNER JOIN author a on a.id = b.author_id)

  1. I get an error
  2. &gt; pg: can&#39;t find column=name in model=Book (try discard_unknown_columns)
  3. </details>
  4. # 答案1
  5. **得分**: 1
  6. 我写了一段代码,每次处理这种情况时都会用到。首先,让我展示代码,然后我会对相关部分进行评论:
  7. ```go
  8. package main
  9. import (
  10. "database/sql"
  11. "fmt"
  12. _ "github.com/lib/pq"
  13. )
  14. type Book struct {
  15. gorm.Model
  16. Title string
  17. Description string
  18. AuthorID uint
  19. Author Author
  20. }
  21. type Author struct {
  22. gorm.Model
  23. FirstName string
  24. LastName string
  25. Books []Book
  26. }
  27. type Result struct {
  28. BookId int
  29. AuthorId int
  30. Title string
  31. FirstName string
  32. LastName string
  33. }
  34. func main() {
  35. conn, err := sql.Open("postgres", "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable")
  36. if err != nil {
  37. panic(err)
  38. }
  39. defer conn.Close()
  40. // 查询
  41. var result []Result
  42. rows, err := conn.Query("select b.id, a.id, b.title, a.first_name, a.last_name from authors a inner join books b on a.id = b.author_id")
  43. if err != nil {
  44. panic(err)
  45. }
  46. defer rows.Close()
  47. for rows.Next() {
  48. var record Result
  49. if err := rows.Scan(&record.BookId, &record.AuthorId, &record.Title, &record.FirstName, &record.LastName); err != nil {
  50. panic(err)
  51. }
  52. result = append(result, record)
  53. }
  54. if err := rows.Err(); err != nil {
  55. panic(err)
  56. }
  57. fmt.Printf("%v", result)
  58. }

结构体定义

BookAuthor 结构体表示我数据库中定义的表。Result 用于保存通过下面指定的查询获取的记录。

查询

查询非常简单。我们只在 main 函数开始时使用 SQL 客户端的 Query 方法。然后,我们需要延迟调用 rows 变量的 Close 方法进行清理。

扫描

for 循环确保我们扫描了 Query 方法检索到的所有行。为了判断是否还有其他行需要获取,我们使用 Next 方法,它返回一个布尔值,指示是否还有其他行需要扫描。
for 循环的主体中,我们声明一个循环作用域变量来保存当前记录。通过 Scan 方法,我们将能够将每个列分配给结构体的相应字段。
最后,我们需要通过在 rows 变量上调用 Err 方法来检查是否有任何错误,并进行处理。

如果这解答了你的问题,请告诉我,谢谢!

英文:

I wrote down a piece of code that I always use when I've to deal with this scenario. First, let me show the code and then I'll comment on the relevant parts:

  1. package main
  2. import (
  3. &quot;database/sql&quot;
  4. &quot;fmt&quot;
  5. _ &quot;github.com/lib/pq&quot;
  6. )
  7. type Book struct {
  8. gorm.Model
  9. Title string
  10. Description string
  11. AuthorID uint
  12. Author Author
  13. }
  14. type Author struct {
  15. gorm.Model
  16. FirstName string
  17. LastName string
  18. Books []Book
  19. }
  20. type Result struct {
  21. BookId int
  22. AuthorId int
  23. Title string
  24. FirstName string
  25. LastName string
  26. }
  27. func main() {
  28. conn, err := sql.Open(&quot;postgres&quot;, &quot;host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable&quot;)
  29. if err != nil {
  30. panic(err)
  31. }
  32. defer conn.Close()
  33. // query
  34. var result []Result
  35. rows, err := conn.Query(&quot;select b.id, a.id, b.title, a.first_name, a.last_name from authors a inner join books b on a.id = b.author_id&quot;)
  36. if err != nil {
  37. panic(err)
  38. }
  39. defer rows.Close()
  40. for rows.Next() {
  41. var record Result
  42. if err := rows.Scan(&amp;record.BookId, &amp;record.AuthorId, &amp;record.Title, &amp;record.FirstName, &amp;record.LastName); err != nil {
  43. panic(err)
  44. }
  45. result = append(result, record)
  46. }
  47. if err := rows.Err(); err != nil {
  48. panic(err)
  49. }
  50. fmt.Printf(&quot;%v&quot;, result)
  51. }

Structs definition

The Book and Author structs represent the tables defined in my database. Result is used to hold the fetched records through the query specified below.

The query

The query is pretty straightforward. We only used the method Query on the SQL client opened at the beginning of the main function. Then, we've to defer a call to the method Close on the rows variable to clean up.

Scanning

The for makes sure that we scan all of the rows retrieved with the Query method. To understand if there are other rows to fetch we use the method Next that returns a bool value indicating whether or not there are other rows to scan.
In the body of the for we declare a loop-scoped variable to hold the current record. Thanks to the Scan method we'll be able to assign each column to the relative field of the struct.
Lastly, we've to check for any error by invoking the method Err on the rows variable and handle it.
Let me know if this clarifies your question, thanks!

huangapple
  • 本文由 发表于 2022年12月18日 19:41:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/74841011.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定