关系模型

在本节中我们将学习模型之间的关系处理。

样例

type User struct {
  ID           uuid.UUID
  Email        string
  Password     string
  Books        Books     `has_many:"books" order_by:"title asc"`
  FavoriteSong Song      `has_one:"song" fk_id:"u_id"`
  Houses       Addresses `many_to_many:"users_addresses"`
}

type Book struct {
  ID      uuid.UUID
  Title   string
  Isbn    string
  User    User        `belongs_to:"user"`
  UserID  uuid.UUID
}

type Song struct {
  ID      uuid.UUID
  Title   string
  UserID  uuid.UUID   `db:"u_id"`
}

type Address struct {
  ID           uuid.UUID
  Street       string
  HouseNumber  int
}

type Books []Book
type Addresses []Address

可用的结构标签

  • has_many: Will load all records from the books table that have a column named user_id, or the column specified with fk_id that matches the User.ID value.
  • belongs_to: Will load a record from users table that have a column named id that matches with Book.UserID value.
  • has_one: Will load a record from the songs table that have a column named user_id, or the column specified with fk_id that matches the User.ID value.
  • many_to_many: Will load all records from the addresses table through the table users_addresses. Table users_addresses MUST define address_id and user_idcolumns to match User.ID and Address.ID values. You can also define a fk_id tag that will be used in the target association i.e. addresses table.
  • fk_id: Defines the column name in the target association that matches model ID. In the example above Song has a column named u_id that represents id of users table. When loading FavoriteSongu_id will be used instead of user_id.
  • order_by: Used in has_many and many_to_many to indicate the order for the association when loading. The format to use is order_by:"<column_name> <asc | desc>"

预加载关联

u := Users{}
err := tx.Eager().Where("name = 'Mark'").All(&u)  // preload all associations for user with name 'Mark', i.e Books, Houses and FavoriteSong

默认情况下Eager会预加载说有的关联数据。有时间我们可能只需要其中一两种,可以调用的指定:

err  = tx.Eager("Books").Where("name = 'Mark'").All(&u) // preload only Books association for user with name 'Mark'.

已经存在的对象加载关联数据

tx.Load(&u) // load all associations for user, i.e Books, Houses and FavoriteSong
tx.Load(&u, "Books") // load only the Books associations for user

创建的时候关联

book := Book{Title: "Pop Book", Description: "Pop Book", Isbn: "PB1"}
tx.Create(&book)
song := Song{Title: "Don't know the title"}
tx.Create(&song)
addr := Address{HouseNumber: 1, Street: "Golang"}
tx.Create(&addr)

user := User{
  Name: "Mark Bates",
  Books: Books{Book{ID: book.ID}},
  FavoriteSong: song,
  Houses: Addresses{
    addr,
  },
}
err := tx.Create(&user)
  1. Books 是 一对多的关系。
  2. FavoriteSong 是一对一的关系。
  3. Houses 是多对多的关系。

而书是属于一个人的。保存的时候将指定user.ID。

book := Book{
   Title:      "Pop Book",
   Description: "Pop Book",
   Isbn:        "PB1",
   User: user,
}
tx.Create(&book)

热创建

上面的列子中各模型都实例化了,也可以采用匿名的方式。

user := User{
  Name: "Mark Bates",
  Books: Books{{Title: "Pop Book", Description: "Pop Book", Isbn: "PB1"}},
  FavoriteSong: Song{Title: "Don't know the title"},
  Houses: Addresses{
    Address{HouseNumber: 1, Street: "Golang"},
  },
}
err := tx.Eager().Create(&user)

属于关系:

book := Book{
   Title:      "Pop Book",
   Description: "Pop Book",
   Isbn:        "PB1",
   User: User{
        Name: nulls.NewString("Larry"),
   },
}
tx.Eager().Create(&book)

一对一模型

type Head struct {
  ID           int
  BodyID       int        `db:"body_id"`
  Body         *Body      `belongs_to:"body"`
}

type Body struct {
  ID           int
  Head         Head       `has_one:"head"`
}
// Eager creation:
// Create a body with its head.
b := &models.Body{
    Head: models.Head{},
}

if err := tx.Eager().Create(b); err != nil {
    return err
}
// Eager fetch all bodies with their head.
bodies = &models.Bodies{}

if err := c.Eager().All(bodies); err != nil {
    log.Printf("err: %v", err)
    return
}

log.Printf("eager fetch: %v", bodies)

本文章首发在 LearnKu.com 网站上。
上一篇 下一篇
superwen
讨论数量: 0
发起讨论 只看当前版本


暂无话题~