學習GORM以前須要理解ORM中的一些概念, 理解這些概念對於流暢使用GORM函數會有很是大的幫助, 嘗試帶着SQL的理念在這裏使用, 最後很容易混淆, 對於GORM的使用也止步於簡單操做, RAW SQLsql
場景: 假設存在卡片card-1/2/3, 卡片之間存在某種關聯關係數組
create cards..
, 當咱們須要建立關聯的時候咱們執行create associations..
→ 所以在傳統SQL觀念裏, 咱們單獨設置出兩張表, 而後有須要來了, 咱們會單獨對這兩張表操做. 下面看看在GORM裏是怎麼作的函數
type Card struct {
gorm.Model
Attribute1 string
Attribute2 string
AssociatedCards []Card
}
複製代碼
→ 與傳統SQL最大的不一樣出現了,在Card結構體裏, 咱們嵌套了一些其餘Card結構體, 傳統SQL中"相互關聯"的概念, 在ORM中成爲了"相互擁有"的概念.工具
一旦能接受新的模式, 就能夠說一說外鍵設定了. 兩個結構體之間相互關聯, 最直接的想法是, 我怎麼從一個結構體 出發而後去得到另外一個結構體,學習
若是我須要經過User去查找它擁有哪些CreditCard, 那麼實際上我作的事情 = "拿着User主鍵去CreditCard表查詢". 這個User的主鍵, 在CreditCard表裏叫什麼名字? 這個名字就是咱們即將設置的外鍵. 請牢記這個概念ui
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
type User struct {
gorm.Model
CreditCards []CreditCard
}
複製代碼
在GORM裏咱們只要建立這兩個表, 關聯關係就生成了, User就會包含不少個CreditCard對象.假設如今你但願經過User去查詢它 關聯了那些卡片, 你能夠這麼作:spa
target := []CreditCard{}
source := &User{
Model:gorm.Model{
ID:1,
},
}
database.Model(source).Related(&target)
複製代碼
繼續外鍵設置的問題, 若是咱們不去指定外鍵名稱, 那麼咱們拿着User主鍵去CreditCard查詢的時候, 默認使用的屬性名:user_id
, 執行:code
select * from credit_cards where user_id = 123;
複製代碼
請注意一個坑, 默認外鍵是: 表名+id,orm
type User struct {
gorm.Model
MemberNumber string
CreditCards []CreditCard `gorm:"foreignkey:UserMemberNumber;association_foreignkey:MemberNumber"`
}
type CreditCard struct {
gorm.Model
Number string
UserMemberNumber string
}
複製代碼
foreignkey
在此以前,CreditCard表裏必需要有User_ID, 做爲外鍵, 可是指定foreign_key以後, 就不是必定要有User_id字段了association_foreignkey
, 在以前咱們都是規定, 必須使用 UserID(主鍵) 去CreditCard表裏查找, 可是使用了這個Tag之後你就能夠經過MemberNumber (非主鍵) 去查找了一旦理解外鍵是怎麼設置的, 咱們就能夠開始用上外鍵了, 概念:Association
是一個籠統的工具, 用於管理全部關聯關係,以上面的Card&User爲例, 咱們來管理以上 兩表之間的關聯關係(上面兩表,採用默認外鍵/主鍵的方式相互關聯)對象
cs := []CreditCard{}
xiaohan := &User{
Model:gorm.Model{
ID:1,
},
}
// 全部與xiaohan(id=1)相關聯的CreditCard,找出來
d.Model(xiaohan).Association("CreditCards").Find(&cs)
// xiaohan數據取消與ID=1的CreditCard取消關聯
d.Model(xiaohan).Association("CreditCards").Delete(&CreditCard{
Model:gorm.Model{
ID:1,
},
})
// xiaohan與CreditCard之間添加關聯
d.Model(xiaohan).Association("CreditCards").Append(&cards)
// 取消全部關聯
db.Model(xiaohan).Association("Languages").Clear()
// 對象關聯計數
db.Model(xiaohan).Association("Languages").Count()
複製代碼
關聯建立的時候存在一個坑,這個坑不注意可能會致使你的數據被抹掉 意識到,User→CreditCard時, 一個User面對的是多個CreditCard →所以在Append裏面填充的是數組,而不是一個單個的對象.
card_id | association_id |
---|---|
card-1 | card-2 |
card-1 | card-3 |
在你建立表之後, AssociationCards
雖然也是一條屬性, 可是並不會像別的字段同樣出如今表裏, 由於在這裏咱們討論的是關聯 這個字段被忽略了, 不會出如今表中.取而代之的是出現了一張表: 名字就叫作card_associations
正如你想表示的那樣, 一個Card對象關聯着許多別的Card對象, 在這張關聯表card_associations
中, 一方面是你的card_id
另外一方面也是你設置的association_id
.
簡單說, 就是你不用手動去設置了,通過這樣描述之後, 表會爲你建立
// 建立一張卡片, 不作任何關聯關係, ID自增
database.Create(&Card{})
// 建立一張卡片, 同時關聯一張卡片
// 這裏若是卡片存在, 直接關聯, 若是不存在則會爲你關聯
database.Create(&Card{
AssociatedCards: []Card{
{
Model:gorm.Model{ID:2},
},
},
})
// 只關聯兩張卡片,將4&7兩張卡片關聯起來
database.Model(&Card{Model:gorm.Model{ID:7}}).
Association("AssociatedCards").
Append(&Card{Model:gorm.Model{ID:4}})
複製代碼
事實上,理解了Association這種思想之後,再去理解Preload就會容易一些, 在GORM裏關聯/外鍵這樣的概念被轉換成結構體之間的相互包含. 繼續上面的例子,聊聊Card之間的"自關聯", 怎麼去查詢id=3
卡片所關聯的卡片?
type Card struct {
ID -> 3
AssociatedCards -> ?
}
// 咱們這樣作:
item := &Card{
Model:gorm.Model{
ID:3,
},
}
database.Preload("AssociatedCards").Find(item)
fmt.Printf("Here the item is %v \n",item)
複製代碼
一級操做:Find 這行代碼的執行過程是這樣的,上來先執行Find(&item)
, 也就是咱們要先查詢出ID=3的對象出來, 既然查出來了, 接下來就能夠查看它關聯了那些卡片了.
二級操做:最外Preload 咱們作Preload, AssociatedCards
是一個屬性, 同時在這裏也象徵了,全部關聯的卡片, 咱們只要取出這一行, 就能拿出全部關聯的屬性
三級操做:次外Preload ...
若是理解以上Preload的執行原理, 以及執行順序之後,咱們就能夠開始在上面玩一些花樣了,咱們查出來的是一些Card對象, 玩的原理是對各級操做作限制, 諸如 order , where , not in 之類的操做
// 對一級操做Find上限制,這裏的where是做用於Find的
database.Where(xxx)
Preload("AssociatedCards").
Find(item)
// 對二級操做上限制 - 排序
database.Preload("AssociatedCards", func(db *gorm.DB) *gorm.DB {
return db.Order("cards.id DESC")
}).Find(item)
// 對二級操做上限制 - 操做
database.Preload("AssociatedCards", "id not in (?)","1,2").Find(item)
複製代碼