Golang Gorm實(shí)現(xiàn)自定義多態(tài)模型關(guān)聯(lián)查詢
更新時(shí)間:2024年11月04日 09:07:03 作者:erternalKing
GORM 是一個(gè)流行的開源 ORM (Object-Relational Mapping) 庫(kù),專為 Go 語(yǔ)言設(shè)計(jì),它簡(jiǎn)化了與 SQL 數(shù)據(jù)庫(kù)的交互,GORM 封裝了數(shù)據(jù)庫(kù)操作,使得開發(fā)者能夠通過(guò)簡(jiǎn)單的鏈?zhǔn)秸{(diào)用來(lái)執(zhí)行 CRUD,本文給大家介紹了Golang Gorm實(shí)現(xiàn)自定義多態(tài)模型關(guān)聯(lián)查詢,需要的朋友可以參考下
一、表結(jié)構(gòu)
CREATE TABLE `orders` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `order_no` varchar(32) NOT NULL DEFAULT '', `orderable_id` int unsigned NOT NULL DEFAULT '0', `orderable_type` char(30) NOT NULL DEFAULT '', `status` tinyint unsigned NOT NULL DEFAULT '0', `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `deleted_at` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; CREATE TABLE `phone` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `phone_name` varchar(50) NOT NULL DEFAULT '', `phone_model` varchar(30) NOT NULL DEFAULT '', `status` tinyint unsigned NOT NULL DEFAULT '0', `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `deleted_at` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; CREATE TABLE `cars` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `car_name` varchar(50) NOT NULL DEFAULT '', `car_model` varchar(30) NOT NULL DEFAULT '', `status` tinyint unsigned NOT NULL DEFAULT '0', `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `deleted_at` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
二、接口定義
// LoaderAble 接口定義數(shù)據(jù)加載行為 type LoaderAble interface { LoadAble(IDs []int) (map[int]any, error) } // LoadAbleItem 接口定義了可加載項(xiàng)的通用方法 type LoadAbleItem interface { GetAbleType() string // 獲取類型鍵值 GetAbleID() int // 獲取ID SetLoadedAbleData(data any) // 設(shè)置加載的數(shù)據(jù) }
三、模型定義并實(shí)現(xiàn)接口
type Order struct { Id int `json:"id"` OrderNo string `json:"order_no"` OrderableId int `json:"orderable_id"` OrderableType string `json:"orderable_type"` Orderable any `json:"orderable" gorm:"-"` Status uint8 `json:"status"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `json:"deleted_at"` } func (tb *Order) TableName() string { return "orders" } func (tb *Order) GetAbleType() string { return tb.OrderableType } func (tb *Order) GetAbleID() int { return tb.OrderableId } func (tb *Order) SetLoadedAbleData(data any) { tb.Orderable = data } //--------------------------------------分割線-------------------------------------- type Car struct { Id int `json:"id"` CarName string `json:"car_name"` CarModel string `json:"car_model"` Status uint8 `json:"status"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `json:"deleted_at"` } func (tb *Car) TableName() string { return "cars" } // CarLoaderAble 實(shí)現(xiàn) Loader 接口 type CarLoaderAble struct{} // LoadAble 具體實(shí)現(xiàn)加載多態(tài)關(guān)聯(lián)邏輯 // IDs 多態(tài)關(guān)聯(lián)類型ID(主要參數(shù)) func (loader *CarLoaderAble) LoadAble(IDs []int) (resultMap map[int]any, err error) { IDsLen := len(IDs) if IDsLen == 0 { return } car := make([]*Car, 0, IDsLen) err = mysql.DefaultMysql.Db.Debug().Where("id IN (?) AND status = ?", IDs, 1).Find(&car).Error if err != nil { return } resultMap = make(map[int]any, IDsLen) for _, item := range car { resultMap[item.Id] = item } return } //--------------------------------------分割線-------------------------------------- type Phone struct { Id int `json:"id"` PhoneName string `json:"phone_name"` PhoneModel string `json:"phone_model"` Status uint8 `json:"status" gorm:"column:status"` StatusNew uint8 `json:"status_new" gorm:"-"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `json:"deleted_at"` } func (tb *Phone) TableName() string { return "phone" } func (tb *Phone) AfterFind(tx *gorm.DB) (err error) { tb.StatusNew = tb.Status return } // PhoneLoaderAble 實(shí)現(xiàn) Loader 接口 type PhoneLoaderAble struct{} // LoadAble 具體實(shí)現(xiàn)加載多態(tài)關(guān)聯(lián)邏輯 // IDs 多態(tài)關(guān)聯(lián)類型ID(主要參數(shù)) func (loader *PhoneLoaderAble) LoadAble(IDs []int) (resultMap map[int]any, err error) { IDsLen := len(IDs) if IDsLen == 0 { return } phone := make([]*Phone, 0, IDsLen) err = mysql.DefaultMysql.Db.Debug().Where("id IN (?) AND status = ?", IDs, 1).Find(&phone).Error if err != nil { return } resultMap = make(map[int]any, IDsLen) for _, item := range phone { resultMap[item.Id] = item } return }
四、創(chuàng)建loader預(yù)加載器
// LoaderAbleFactory 用于管理不同類型的加載器 type LoaderAbleFactory struct { loaders map[string]LoaderAble } func NewLoaderAbleFactory() *LoaderAbleFactory { return &LoaderAbleFactory{ loaders: make(map[string]LoaderAble), } } func (f *LoaderAbleFactory) RegisterLoader(typeName string, loader LoaderAble) { f.loaders[typeName] = loader }
五、注冊(cè)loader預(yù)加載器服務(wù)
var ( loaderAbleFactory *LoaderAbleFactory ) // init 選擇在項(xiàng)目啟動(dòng)初始化時(shí)進(jìn)行全局加載 func init() { loaderAbleFactory = NewLoaderAbleFactory() loaderAbleFactory.RegisterLoader("phone", &PhoneLoaderAble{}) loaderAbleFactory.RegisterLoader("car", &CarLoaderAble{}) log.Println("多態(tài)模型關(guān)系注冊(cè)成功...") }
六、實(shí)現(xiàn)LoadAble通用的加載函數(shù)
// LoadAble 通用的加載函數(shù),可以處理任何實(shí)現(xiàn)了 LoadableItem 接口的切片 func LoadAble[T LoadAbleItem](items []T) error { if len(items) == 0 { return nil } // 按類型分組收集ID typeIDsMap := make(map[string][]int) for _, item := range items { typeKey := item.GetAbleType() typeIDsMap[typeKey] = append(typeIDsMap[typeKey], item.GetAbleID()) } // 使用對(duì)應(yīng)的loader加載數(shù)據(jù) typeDataMap := make(map[string]map[int]any) for typeName, ids := range typeIDsMap { loader, ok := loaderAbleFactory.loaders[typeName] if !ok { continue } resultMap, err := loader.LoadAble(ids) if err != nil { return err } typeDataMap[typeName] = resultMap } // 填充數(shù)據(jù) for _, item := range items { if dataMap, ok := typeDataMap[item.GetAbleType()]; ok { if data, exists := dataMap[item.GetAbleID()]; exists { item.SetLoadedAbleData(data) } } } return nil }
七、調(diào)試
- 準(zhǔn)備數(shù)據(jù)
--orders表 INSERT INTO `orders` (`id`, `order_no`, `orderable_id`, `orderable_type`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES (1, '202411010001', 1002, 'car', 1, '2024-11-01 12:03:03', '2024-11-01 12:03:06', NULL); INSERT INTO `orders` (`id`, `order_no`, `orderable_id`, `orderable_type`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES (2, '202411010002', 1001, 'phone', 1, '2024-11-01 12:03:03', '2024-11-01 12:03:06', NULL); INSERT INTO `orders` (`id`, `order_no`, `orderable_id`, `orderable_type`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES (3, '202411010003', 1000, 'car', 1, '2024-11-01 12:03:03', '2024-11-01 12:03:06', NULL); INSERT INTO `orders` (`id`, `order_no`, `orderable_id`, `orderable_type`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES (4, '202411010004', 1001, 'car', 1, '2024-11-01 12:03:03', '2024-11-01 12:03:06', NULL); INSERT INTO `orders` (`id`, `order_no`, `orderable_id`, `orderable_type`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES (5, '202411010005', 1002, 'phone', 1, '2024-11-01 12:03:03', '2024-11-01 12:03:06', NULL); --phone表 INSERT INTO `phone` (`id`, `phone_name`, `phone_model`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES (1000, 'XiaoMi', '2S', 2, '2024-11-01 11:59:37', '2024-11-01 11:59:40', NULL); INSERT INTO `phone` (`id`, `phone_name`, `phone_model`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES (1001, 'HUAWEI', 'mate60', 1, '2024-11-01 11:59:54', '2024-11-01 11:59:57', NULL); INSERT INTO `phone` (`id`, `phone_name`, `phone_model`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES (1002, 'Apple', 'iPhone 12 Pro Max', 1, '2024-11-01 12:00:26', '2024-11-01 12:00:28', NULL); --cars表 INSERT INTO `cars` (`id`, `car_name`, `car_model`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES (1000, '奧迪', 'A6L', 1, '2024-11-01 11:57:53', '2024-11-01 11:57:55', NULL); INSERT INTO `cars` (`id`, `car_name`, `car_model`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES (1001, '寶馬', '5系', 1, '2024-11-01 11:58:12', '2024-11-01 11:58:15', NULL); INSERT INTO `cars` (`id`, `car_name`, `car_model`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES (1002, '奔馳', 'E300', 1, '2024-11-01 11:58:53', '2024-11-01 11:58:56', NULL);
- 編寫代碼
// Gin框架+Gorm為例 api.GET("/orders", controller.GetOrderList) // GetOrderList 獲取訂單列表接口 func GetOrderList(c *gin.Context) { orders := make([]*model.Order, 0) err := mysql.DefaultMysql.Db.Debug().Find(&orders).Error if err != nil { c.JSON(200, gin.H{"error": err.Error()}) return } err = model.LoadAble(orders) if err != nil { c.JSON(200, gin.H{"error": err.Error()}) return } c.JSON(200, gin.H{"data": orders}) }
- 發(fā)起請(qǐng)求
curl '127.0.0.1:16888/api/orders'
{ "data": [ { "id": 1, "order_no": "202411010001", "orderable_id": 1002, "orderable_type": "car", "orderable": { "id": 1002, "car_name": "奔馳", "car_model": "E300", "status": 1, "created_at": "2024-11-01T11:58:53+08:00", "updated_at": "2024-11-01T11:58:56+08:00", "deleted_at": null }, "status": 1, "created_at": "2024-11-01T12:03:03+08:00", "updated_at": "2024-11-01T12:03:06+08:00", "deleted_at": null }, { "id": 2, "order_no": "202411010002", "orderable_id": 1001, "orderable_type": "phone", "orderable": { "id": 1001, "phone_name": "HUAWEI", "phone_model": "mate60", "status": 1, "status_new": 1, "created_at": "2024-11-01T11:59:54+08:00", "updated_at": "2024-11-01T11:59:57+08:00", "deleted_at": null }, "status": 1, "created_at": "2024-11-01T12:03:03+08:00", "updated_at": "2024-11-01T12:03:06+08:00", "deleted_at": null }, { "id": 3, "order_no": "202411010003", "orderable_id": 1000, "orderable_type": "car", "orderable": { "id": 1000, "car_name": "奧迪", "car_model": "A6L", "status": 1, "created_at": "2024-11-01T11:57:53+08:00", "updated_at": "2024-11-01T11:57:55+08:00", "deleted_at": null }, "status": 1, "created_at": "2024-11-01T12:03:03+08:00", "updated_at": "2024-11-01T12:03:06+08:00", "deleted_at": null }, { "id": 4, "order_no": "202411010004", "orderable_id": 1001, "orderable_type": "car", "orderable": { "id": 1001, "car_name": "寶馬", "car_model": "5系", "status": 1, "created_at": "2024-11-01T11:58:12+08:00", "updated_at": "2024-11-01T11:58:15+08:00", "deleted_at": null }, "status": 1, "created_at": "2024-11-01T12:03:03+08:00", "updated_at": "2024-11-01T12:03:06+08:00", "deleted_at": null }, { "id": 5, "order_no": "202411010005", "orderable_id": 1002, "orderable_type": "phone", "orderable": { "id": 1002, "phone_name": "Apple", "phone_model": "iPhone 12 Pro Max", "status": 1, "status_new": 1, "created_at": "2024-11-01T12:00:26+08:00", "updated_at": "2024-11-01T12:00:28+08:00", "deleted_at": null }, "status": 1, "created_at": "2024-11-01T12:03:03+08:00", "updated_at": "2024-11-01T12:03:06+08:00", "deleted_at": null } ] }
以上就是Golang Gorm實(shí)現(xiàn)自定義多態(tài)模型關(guān)聯(lián)查詢的詳細(xì)內(nèi)容,更多關(guān)于Golang Gorm關(guān)聯(lián)查詢的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解go語(yǔ)言 make(chan int, 1) 和 make (chan int) 的區(qū)別
這篇文章主要介紹了go語(yǔ)言 make(chan int, 1) 和 make (chan int) 的區(qū)別,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01golang1.23版本之前 Timer Reset方法無(wú)法正確使用
在Go 1.23之前,使用`time.Reset`函數(shù)時(shí)需要先調(diào)用`Stop`并明確從timer的channel中抽取出東西,以避免潛在的問(wèn)題,然而,這在實(shí)際代碼中難以實(shí)現(xiàn),因?yàn)樵O(shè)置定時(shí)器狀態(tài)和發(fā)送channel的操作并不是原子的,在某些情況下,這會(huì)導(dǎo)致timer在不應(yīng)該觸發(fā)時(shí)提前觸發(fā)2025-01-01Golang實(shí)現(xiàn)AES對(duì)稱加密算法實(shí)例詳解
所謂對(duì)稱加密是指在加密和解碼時(shí)使用同一密鑰的加密方式,下面這篇文章主要給大家介紹了關(guān)于Golang實(shí)現(xiàn)AES對(duì)稱加密算法的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02