GORM-V1-关联

说明

请先阅读官方文档,由于官方文档对每个例子和概念解释比较简单,官方文档中个人认为比较难理解的概念在正文章节进行解释

本文须与官方文档伴食,否则将不知所云。

可对应 学习项目 实践验证。

参考

正文

关系

foreignkey & association foreignkey

//情况A:不指定外键和关联外键
type User struct {
    gorm.Model
    CreditCard   CreditCard
}

type CreditCard struct {
    gorm.Model
    UserID   uint
    Number   string
}
//情况B:外键和关联外键
type User struct {
    gorm.Model
  	Refer   string
    CreditCard   CreditCard `gorm:"ForeignKey:ReferRela;AssociationForeignKey:Refer"`
}

type CreditCard struct {
    gorm.Model
    ReferRela   uint
    Number   string
}

理解:

  • 在情况A下,默认credit_cards.user_idForeignKey,对应users.idAssociationForeignKey,即某条users表的记录id=1234,那么credit_cards表中的user_id=1234的记录属于与其对应;
  • 在情况B下,由于显式指定了外键和关联外键,则credit_cards.refer_rela对应users.refer

后文多种关系中都涉及此两键,但是在 Many to Many 关联关系中使用方式稍有不同。

  • foreignkey:B 表关联 A 表的字段
  • association foreignkey:A 表被 B 表关联的字段

即:A 表的association foreignkey对应 B表的foreignkey,两表两值相等的记录具有关联关系。

后文多种关系中都涉及此两个键,用法是一样的。默认不指定的时候 A 表的association foreignkey为其primary key,B 表的foreignkey为 A 表表名+A 表 primary key

Belongs To & Has One

//Profile Belongs To User
type User struct {
  gorm.Model
  Name string
}

// `Profile` 属于 `User`, 外键是`UserID` 
type Profile struct {
  gorm.Model
  UserID int
  User   User
  Name   string
}
//User Has One Profile
type User struct {
  gorm.Model
  Name string
  Profile Profile
}

// `Profile` 属于 `User`, 外键是`UserID` 
type Profile struct {
  gorm.Model
  UserID int
  Name   string
}

理解:

两者区别在于主体(主语)不同,在逻辑上孪生:

  • Belongs To :以 Profile 为主体,Profile属于 User。——Profile 内持有 User;
  • Has One:以 User 为主体,User 拥有 Profile。——User 内持有 Profile。

两者的ForeignKeyAssociationForeignKey关系是一样的,都是在 Profile 里定义ForeignKey——Profile.UserID,其对应的是User的PrimerKey(即AssociationForeignKey)——User.ID

根据以上两种定义方式在数据库创建表结构没有差别,但在应用程序内对数据操作有区别(设计目的|效果)。就查询而言,前者可以查询出携带对应 User 信息的 Profile;后者可以查询出携带对应 Profile 信息的 User。

多态关联

Many To Many中不能使用多态关联

type Cat struct {
    Id    int
    Name  string
    Toy   Toy `gorm:"polymorphic:Owner;"`
  }

  type Dog struct {
    Id   int
    Name string
    Toy  Toy `gorm:"polymorphic:Owner;"`
  }

  type Toy struct {
    Id        int
    Name      string
    OwnerId   int
    OwnerType string
  }

理解:toys.owner_id对应cats.iddogs.idtoys.owner_type对应catdog

Has Many & Many To Many

  • 通过切片指定对多关系

  • `gorm:"many2many:关系表命;"`指定多对多关系

  • Many To Manyforeignkey & association foreignkey不做方向区分,都是指定关系表对应的实体表字段

  • association_jointable_foreignkey&jointable_foreignkey指定关系表中字段名

关系的使用

通过 gorm.DB.Set(xxx) 或者 Struct Tag 定义关系行为:

  • gorm:association_autoupdate——自动更新关联开关
  • gorm:association_autocreate——自动创建关联开关
  • gorm: save_associations——前两者的和
  • gorm:association_save_reference——关联引用保存开关
// Set set setting by name, which could be used in callbacks, will clone a new db, and update its setting
func (s *DB) Set(name string, value interface{}) *DB {
   return s.clone().InstantSet(name, value)
}

根据 Set 方法的注释说明,返回的是 DB 的副本,则此设置只在一次 DB 构造执行中有效。

方法

 db.Model(&user).Association("Languages")
 指定表、记录 ID
 指定字段
 后面跟操作方法如下
  • Find(&languages)——查询匹配的关联记录
  • Append(Language{Name: "DE"})——添加关联
  • Replace([]Language{languageZH, languageEN})——替换关联
  • Delete([]Language{languageZH, languageEN})——删除关联
  • Clear()——清空关联
  • Count()——返回关联记录数量

Preloading (预加载)

Preload("Orders")Find(&users)实际作用与语义刚好相反。

  • 从方法语义来说,只管感觉是加载 Orders 表记录,根据 Orders 记录查询所有关联的 Users 记录
  • 实际过程是,加载 Users 记录,更具 Users 记录查询关联的 Orders 记录

并且可以在 Preload 内指定 Orders 的筛选条件,可以配合 Where 方法指定 Users 的筛选条件。

生老病死过于平淡,唯有求知聊以慰藉。
原文地址:https://www.cnblogs.com/wangbs95/p/13859640.html