当前位置: 代码网 > it编程>前端脚本>Golang > Golang Gorm实现自定义多态模型关联查询

Golang Gorm实现自定义多态模型关联查询

2024年11月26日 Golang 我要评论
一、表结构create table `orders` ( `id` int unsigned not null auto_increment, `order_no` varchar(32) not

一、表结构

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关联查询的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com