# gorm
https://juejin.cn/post/7198357438840406071
https://blog.csdn.net/jingghe/article/details/121642665
find 解析
https://juejin.cn/post/7287131174266994745
## v2 vs v1
v2 链式调用一定要记得最后用 .Error 去拿错误。v1 有些方法返回 (DB, error),v2 都改成只返回 *gorm.DB,你从它身上取 Error。
## 踩坑
## 源碼解讀
https://zhuanlan.zhihu.com/p/663707360
https://liudon.com/posts/how-gorm-generates-sql/
## log 顯示

## 自定義數據
## 自定義序列化

實現scan 跟value
雖然一樣是scan 跟value但參數不一樣
記住 他是到gorm前
自定義數據是 gorm 到db
## uuid
如果使用db的uuid產生

這邊tag要加上default 不然他不會吃到 我也不知道為什麼

## strcut 轉 strcut

## 讀寫分離

## connect
如果用sql.Open在去連線的話
要注意sql.Open那邊有沒有close
因為gorm會自動處理close的部分
## 只要欄位不用struct
```
func (t *TicketRepo) GetSellTimeRange(ctx context.Context, tx *gorm.DB, idList []int64) (sellStartAt, sellEndAt sql.NullTime, err error) {
if tx == nil {
tx = t.Orm()
}
query := `
SELECT MIN(sell_start_at) as sell_start_at,
MAX(sell_end_at) as sell_end_at
FROM tickets
WHERE id IN (?)`
row := tx.WithContext(ctx).Raw(query, idList).Row()
if err := row.Scan(&sellStartAt, &sellEndAt); err != nil {
return sql.NullTime{}, sql.NullTime{}, err
}
return sellStartAt, sellEndAt, nil
}
```
## 表達式
```
db.Clauses(clause.OrderBy{
Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{[]int{1, 2, 3}}, WithoutParentheses: true},
}).Find(&User{})
// SELECT * FROM users ORDER BY FIELD(id,1,2,3)
```
可以自己用建立 Clauses 裡面可以去找對應的orderBy或其他的
然後在用expr去寫raw sql
### 条件表达式
如果你想构建一些查询 helper,你可以让 struct 实现 clause.Expression 接口:

上面json操作等於 like只能用下面方法喔

## hook 可以傳入值

可以像是你紀錄log用
讀取用InstanceGet


## 指定model

## first find
因為你傳入point了 所以他可以直接用struct的table name
function 不用再指定對應的model

以上是指用model指定或 直接find first的傳入
如果是用table要注意
不能用first or find 他們是一定要指定struct

當然你也可以用匿名的 但記得first or find 一定要struct

## chain

如果做任何where都會getInstan
所以只要將它賦值 之後一直連接條件就不用重新賦值了
如果要新的就newSession 但建議直接傳入的db 去做就好
當然也可以newDB 比較是subQuery所以這種比較少用到
## where
query with struct 只會用非零

但struct可以用指定欄位 可以用到非零

### 差異
find找不到可以用.RecordNotFound判斷
first會丟出errRecordNotFound error


## scan vs find
http://foreversmart.cc/go/the-difference-of-gorm-scan-and-find/
### scan vs pluck
Scan 和 Pluck 都可以用來從結果中讀取單個欄位,但是用法略有不同:
Scan 將查詢結果映射到一個結構體或一個變量中。如果查詢返回多行結果,只有第一行會被掃描到,其它行會被忽略。如果查詢沒有結果,則掃描結構體或變量的值將保持不變。
Pluck 將查詢結果映射到一個切片中。切片的元素類型必須是和查詢結果中該欄位相同的類型。如果查詢沒有結果,則切片將保持為空切片。
簡單來說,如果你只需要查詢結果中的一個欄位,而不需要其他欄位,那麼可以使用 Pluck 或 Scan。如果你需要查詢結果中的多個欄位,或者需要將結果映射到一個結構體中,那麼應該使用 Scan。
## limit
通过 -1 消除 Offset 条件
## select
可以

## update vs updates
update的model一定要有id
db.Model(&user)
## clause

## gorm添加数据库排他锁,for update
https://blog.csdn.net/juzipidemimi/article/details/104502385
## 批量插入

## save vs update
Save函數將為不存在的實體創建主鍵以及更新字段,而 Update只會更新字段。
## updates


小心zero-value
## gorm
https://learnku.com/docs/gorm/v2/v2_release_note/9756
### PostgreSQL
https://myapollo.com.tw/zh-tw/golang-gorm-postgresql-jsonb/
### 嵌入结构体

对于正常的结构体字段,你也可以通过标签 embedded 将其嵌入

并且,您可以使用标签 embeddedPrefix 来为 db 中的字段名添加前缀,例如

### 使用 SQL 表达式、Context Valuer 创建记录
https://learnku.com/docs/gorm/v2/create/9732
### 默认值

**注意 像 0、''、false 等零值,不会将这些字段定义的默认值保存到数据库。您需要使用指针类型或 Scanner/Valuer 来避免这个问题,例如:**

## orderBy

### zero value
当通过结构体进行查询时,GORM将会只通过非零值字段查询,这意味着如果你的字段值为0,'', false 或者其他 零值时,将不会被用于构建查询条件


### first, last ....
First、Last 方法会根据主键查找到第一个、最后一个记录, 它仅在通过 struct 或提供 model 值进行查询时才起作用。 如果 model 类型没有定义主键,则按第一个字段排序,例如:


注意如果放入實例化 就會按照第一字段排序
## firOrCreate, FirstOrInit
### Assign vs Attrs
Assign 算是另外條件 laravel updateOrcreate的感覺 可看下面用到的updateOrCreate
當你沒找到 要insert的欄位

Attrs -> 沒找到 加上條件create
-> 找到 根據條件更新
Assign -> 沒找到 加上條件create
-> 找到。加上條件更新
## 关联创建

根据 map 创建记录时,association 不会被调用,且主键也不会自动填充
## updateOrCreate
https://juejin.cn/post/7155840164504272933
https://stackoverflow.com/questions/39333102/how-to-create-or-update-a-record-with-gorm


這種也是
需要根據唯一鍵來進行判斷,那就可以使用第一種做法
比較合理 因為他是補捉衝突的情況
Assign 函式,該函式只會更新傳入參數不為零值的欄位
## 自定义数据类型
json rawMessage or
pq.StringArray
datatypes.JSON(可以看他怎實現的 參考)


自定義也能用hook喔

https://github.com/go-gorm/datatypes
很多可以參考
記住 這些都要升級版本

## Upsert 及冲突

都用AssignmentColumns 第一個postgres沒有支援
## 原始碼分析
https://cloud.tencent.com/developer/article/1881967
https://jiajunhuang.com/articles/2019_03_19-gorm.md.html
### query
https://segmentfault.com/a/1190000019490869
## 表达式

## tag


## Associations
### Associations
model可以直接放id, 只能id

搭配where condition (這裡使用 where 的條件會套用到 categories 上)

### Replace Association
## create_at and update_at

## callback
https://juejin.cn/post/7097999127300014093
https://eddycjy.gitbook.io/golang/di-3-ke-gin/gorm-callback

作法有變 看文黨
## 分頁
## clause
https://blog.csdn.net/dorlolo/article/details/127238144

特殊可自訂

在對應的基本cluase 上面加上對應的modifier
所以對於

你如果是基本的cluase interface你就可以直接傳入
如果是modifyStamement
可以用軟刪除跟hint
hint目前支援三個

## join

## distinct

## select

## or
![Uploading file..._c45t7e6ng]()
複雜可以用stuct不然看很累
## where

struct一定要指定欄位 不然零值不會被查詢
## 軟刪


https://blog.csdn.net/dorlolo/article/details/127238144

詳解
https://juejin.cn/post/7151565238259679240
非常詳細
他是直接在sql上改變
跟用callback不一樣
callback是直接註冊到hook上
flag

## 刪除

## time
https://studygolang.com/articles/35739
###### tags: `Go`