gorm 教程二(2)

简介: gorm 教程二

gorm 教程二(1)https://developer.aliyun.com/article/1391739


反向关联

// 用户拥有并且属于多种语言,使用 `user_languages` 作为中间表
type User struct {
    gorm.Model
    Languages         []*Language `gorm:"many2many:user_languages;"`
}
type Language struct {
    gorm.Model
    Name string
    Users               []*User     `gorm:"many2many:user_languages;"`
}
db.Model(&language).Related(&users)
 SELECT * FROM "users" INNER JOIN "user_languages" ON "user_languages"."user_id" = "users"."id" WHERE  ("user_languages"."language_id" IN ('111'))

外键

type CustomizePerson struct {
  IdPerson string             `gorm:"primary_key:true"`
  Accounts []CustomizeAccount `gorm:"many2many:PersonAccount;association_foreignkey:idAccount;foreignkey:idPerson"`
}
type CustomizeAccount struct {
  IdAccount string `gorm:"primary_key:true"`
  Name      string
}

外键会为两个结构体创建一个多对多的关系,并且这个关系将通过外键customize_person_id_person 和 customize_account_id_account 保存到中间表 PersonAccount。

中间表外键

如果你想改变中间表的外键,你可以用标签 association_jointable_foreignkey, jointable_foreignkey

type CustomizePerson struct {
  IdPerson string             `gorm:"primary_key:true"`
  Accounts []CustomizeAccount `gorm:"many2many:PersonAccount;foreignkey:idPerson;association_foreignkey:idAccount;association_jointable_foreignkey:account_id;jointable_foreignkey:person_id;"`
}
type CustomizeAccount struct {
  IdAccount string `gorm:"primary_key:true"`
  Name      string
}

自引用

为了定义一个自引用的多对多关系,你不得不改变中间表的关联外键。

和来源表外键不同的是它是通过结构体的名字和主键生成的,例如:

type User struct {
  gorm.Model
  Friends []*User `gorm:"many2many:friendships;association_jointable_foreignkey:friend_id"`
}

GORM 将创建一个带外键 user_id 和 friend_id 的中间表, 并且使用它去保存用户表的自引用关系。

然后你可以像普通关系一样操作它, 例如:

DB.Preload("Friends").First(&user, "id = ?", 1)
DB.Model(&user).Association("Friends").Append(&User{Name: "friend1"}, &User{Name: "friend2"})
DB.Model(&user).Association("Friends").Delete(&User{Name: "friend2"})
DB.Model(&user).Association("Friends").Replace(&User{Name: "new friend"})
DB.Model(&user).Association("Friends").Clear()
DB.Model(&user).Association("Friends").Count()

使用多对多

db.Model(&user).Related(&languages, "Languages")
 SELECT * FROM "languages" INNER JOIN "user_languages" ON "user_languages"."language_id" = "languages"."id" WHERE "user_languages"."user_id" = 111
//  当查询用户时预加载 Language
db.Preload("Languages").First(&user)

关联

自动创建/更新

GORM 将在创建或保存一条记录的时候自动保存关联和它的引用,如果关联有一个主键, GORM 将调用 Update 来更新它, 不然,它将会被创建。

user := User{
    Name:            "jinzhu",
    BillingAddress:  Address{Address1: "Billing Address - Address 1"},
    ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
    Emails:          []Email{
        {Email: "jinzhu@example.com"},
        {Email: "jinzhu-2@example@example.com"},
    },
    Languages:       []Language{
        {Name: "ZH"},
        {Name: "EN"},
    },
}
db.Create(&user)
 BEGIN TRANSACTION;
 INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1");
 INSERT INTO "addresses" (address1) VALUES ("Shipping Address - Address 1");
 INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
 INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com");
 INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu-2@example.com");
 INSERT INTO "languages" ("name") VALUES ('ZH');
 INSERT INTO user_languages ("user_id","language_id") VALUES (111, 1);
 INSERT INTO "languages" ("name") VALUES ('EN');
 INSERT INTO user_languages ("user_id","language_id") VALUES (111, 2);
 COMMIT;
db.Save(&user)

关闭自动更新

如果你的关联记录已经存在在数据库中, 你可能会不想去更新它。

你可以设置 gorm:association_autoupdate 为 false

// 不更新有主键的关联,但会更新引用
db.Set("gorm:association_autoupdate", false).Create(&user)
db.Set("gorm:association_autoupdate", false).Save(&user)
或者使用 GORM 的标签, gorm:"association_autoupdate:false"
type User struct {
  gorm.Model
  Name       string
  CompanyID  uint
  // 不更新有主键的关联,但会更新引用
  Company    Company `gorm:"association_autoupdate:false"`
}

关闭自动创建

即使你禁用了 AutoUpdating, 仍然会创建没有主键的关联,并保存它的引用。

你可以通过把 gorm:association_autocreate 设置为 false 来禁用这个行为。

// 不创建没有主键的关联,不保存它的引用。
db.Set("gorm:association_autocreate", false).Create(&user)
db.Set("gorm:association_autocreate", false).Save(&user)
或者使用 GORM 标签, gorm:"association_autocreate:false"
type User struct {
  gorm.Model
  Name       string
  // 不创建没有主键的关联,不保存它的引用。
  Company1   Company `gorm:"association_autocreate:false"`
}

关闭自动创建/更新

禁用 AutoCreate 和 AutoUpdate,你可以一起使用它们两个的设置。

db.Set("gorm:association_autoupdate", false).Set("gorm:association_autocreate", false).Create(&user)
type User struct {
  gorm.Model
  Name    string
  Company Company `gorm:"association_autoupdate:false;association_autocreate:false"`
}

或者使用 gorm:save_associations

db.Set("gorm:save_associations", false).Create(&user)
db.Set("gorm:save_associations", false).Save(&user)
type User struct {
  gorm.Model
  Name    string
  Company Company `gorm:"association_autoupdate:false"`
}

关闭保存引用

如果你不想当更新或保存数据的时候保存关联的引用, 你可以使用下面的技巧

db.Set("gorm:association_save_reference", false).Save(&user)
db.Set("gorm:association_save_reference", false).Create(&user)
或者使用标签
type User struct {
  gorm.Model
  Name       string
  CompanyID  uint
  Company    Company `gorm:"association_save_reference:false"`
}

关联模式

关联模式包含一些可以轻松处理与关系相关的事情的辅助方法。

// 开启关联模式
var user User
db.Model(&user).Association("Languages")
// `user` 是源表,必须包含主键
// `Languages` 是源表关系字段名称。
// 只有上面两个条件都能匹配,关联模式才会生效, 检查是否正常:
// db.Model(&user).Association("Languages").Error

查找关联

查找匹配的关联

db.Model(&user).Association("Languages").Find(&languages)

增加关联

为 many to many, has many 新增关联, 为 has one, belongs to 替换当前关联

db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Append(Language{Name: "DE"})

替换关联

用一个新的关联替换当前关联

db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)

删除关联

删除源和参数对象之间的关系, 只会删除引用,不会删除他们在数据库中的对象。

db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Delete(languageZH, languageEN)

清理关联

删除源和当前关联之间的引用,不会删除他们的关联

db.Model(&user).Association("Languages").Clear()

统计关联

返回当前关联的统计数

db.Model(&user).Association("Languages").Count()

预加载

预加载

db.Preload("Orders").Find(&users)
 SELECT * FROM users;
 SELECT * FROM orders WHERE user_id IN (1,2,3,4);
db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
 SELECT * FROM users;
 SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');
db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
 SELECT * FROM users WHERE state = 'active';
 SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');
db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
 SELECT * FROM users;
 SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
 SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
 SELECT * FROM roles WHERE id IN (4,5,6); // belongs to

自动预加载

始终自动预加载的关联

type User struct {
  gorm.Model
  Name       string
  CompanyID  uint
  Company    Company `gorm:"PRELOAD:false"` //没有预加载
  Role       Role                           // 已经预加载
}
db.Set("gorm:auto_preload", true).Find(&users)

嵌套预加载

db.Preload("Orders.OrderItems").Find(&users)
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)

自定义预加载 SQL

您可以通过传入func(db * gorm.DB)* gorm.DB来自定义预加载SQL,例如:

db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
    return db.Order("orders.amount DESC")
}).Find(&users)
 SELECT * FROM users;
 SELECT * FROM orders WHERE user_id IN (1,2,3,4) order by orders.amount DESC;
相关文章
|
应用服务中间件 数据库 AHAS
gorm 一对一关系 以及 关联的操作
gorm 一对一关系 以及 关联的操作
263 0
VSCode调试 添加命令行参数
VSCode调试 添加命令行参数
677 0
|
SQL 大数据 关系型数据库
开源大数据比对平台(dataCompare)新版本发布
开源大数据比对平台(dataCompare)新版本发布
846 0
|
设计模式 前端开发 JavaScript
观察者模式 vs 发布-订阅模式:两种设计模式的对决!
欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。
|
11月前
|
缓存 安全 UED
网站图片缓存设置不当可能会导致哪些问题?
【10月更文挑战第18天】网站图片缓存的合理设置至关重要,需要综合考虑图片的性质、更新频率、用户体验、服务器性能等多方面因素,以避免出现上述各种问题,确保网站的正常运行和用户信息的安全。
|
6月前
|
人工智能 测试技术 API
PaperBench:OpenAI开源AI智能体评测基准,8316节点精准考核复现能力
PaperBench是OpenAI推出的开源评测框架,通过8316个评分节点系统评估AI智能体复现学术论文的能力,涵盖理论理解、代码实现到实验执行全流程。
355 30
PaperBench:OpenAI开源AI智能体评测基准,8316节点精准考核复现能力
|
SQL 数据采集 存储
"揭秘SQL Server中REPLACE函数的神奇力量!一键替换字符串,解锁数据处理的无限可能,你还在等什么?"
【8月更文挑战第20天】SQL Server 的 REPLACE 函数是处理字符串的强大工具,用于在查询中替换字符串的部分内容。基本语法为 `REPLACE(string_expression, string_pattern, string_replacement)`。例如,可将员工邮箱从 `@example.com` 替换为 `@newdomain.com`。支持多级嵌套替换与变量结合使用,适用于动态生成查询。注意大小写敏感性及全局替换特性。掌握 REPLACE 函数能有效提升数据处理能力。
673 0
|
10月前
|
机器学习/深度学习 Web App开发 人工智能
Amurex:开源AI会议助手,提供实时建议、智能摘要、快速回顾关键信息
Amurex是一款开源的AI会议助手,提供实时建议、智能摘要、快速回顾关键信息等功能,帮助用户提升会议效率。本文将详细介绍Amurex的功能、技术原理以及如何运行和使用该工具。
429 18
Amurex:开源AI会议助手,提供实时建议、智能摘要、快速回顾关键信息
|
10月前
|
存储 弹性计算 数据管理
阿里云对象存储OSS收费标准:存储、流量和请求等多个计费项详解
阿里云对象存储OSS提供多样化的计费模式,涵盖存储、流量、请求等多项费用。存储费用方面,按量付费标准型为0.09元/GB/月,包年包月则有9元40GB等多种选择。流量费用仅对公网出方向收费,价格区间从0.25至0.50元/GB不等,支持按量付费与流量包抵扣两种方式。更多详情及精准报价,欢迎访问阿里云OSS官方页面。
6626 1
|
11月前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
876 4