一、表结构
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 接口定义数据加载行为 type loaderable interface { loadable(ids []int) (map[int]any, error) } // loadableitem 接口定义了可加载项的通用方法 type loadableitem interface { getabletype() string // 获取类型键值 getableid() int // 获取id setloadedabledata(data any) // 设置加载的数据 }
三、模型定义并实现接口
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 实现 loader 接口 type carloaderable struct{} // loadable 具体实现加载多态关联逻辑 // ids 多态关联类型id(主要参数) 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 实现 loader 接口 type phoneloaderable struct{} // loadable 具体实现加载多态关联逻辑 // ids 多态关联类型id(主要参数) 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 }
四、创建loader预加载器
// 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 }
五、注册loader预加载器服务
var ( loaderablefactory *loaderablefactory ) // init 选择在项目启动初始化时进行全局加载 func init() { loaderablefactory = newloaderablefactory() loaderablefactory.registerloader("phone", &phoneloaderable{}) loaderablefactory.registerloader("car", &carloaderable{}) log.println("多态模型关系注册成功...") }
六、实现loadable通用的加载函数
// loadable 通用的加载函数,可以处理任何实现了 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()) } // 使用对应的loader加载数据 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 } // 填充数据 for _, item := range items { if datamap, ok := typedatamap[item.getabletype()]; ok { if data, exists := datamap[item.getableid()]; exists { item.setloadedabledata(data) } } } return nil }
七、调试
- 准备数据
--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}) }
- 发起请求
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实现自定义多态模型关联查询的详细内容,更多关于golang gorm关联查询的资料请关注代码网其它相关文章!
发表评论