一、表结构
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关联查询的资料请关注代码网其它相关文章!
发表评论