SQL的连接查询可以将多个表的数据查询出来,形成一个中间表。在sql中为JOIN
关键字。最常用的是LEFT JOIN
,RIGHT JOIN
,INNER JOIN
,OUTER JOIN
。
xorm框架是一个基于go语言的ORM框架,也支持连接查询。由于xom和原生sql查询也支持基于xorm方法的查询,因此本文将基于两种不同的方法进行比较。
select order_item.id,order_item.order_id,order_item.product_name,order_item.product_id,order_item.product_area_id,order_item.card_type,order_item.card_num,order_item.container_name
,order_item.container_id,order_item.using_cpu,order_item.using_ram,order_item.video_memory,order_item.free_data_disk,order_item.expand_data_disk,order_item.max_cuda_version,order_item.container_name
,order_item.charge_mode,order_item.rent_start_time,order_item.rent_end_time,order_item.deleted_at,order_item.created_at,order_item.updated_at
,order_main.id as oid,order_main.customer_id as ocustomer_id ,order_main.order_amount as order_amount
from order_item LEFT JOIN order_main on order_item.order_id = order_main.id where order_main.customer_id = '1970' and order_main.order_id = '1'
如上面所示为一个LEFT JOIN
的左连接查询,可以看到使用sql语句,需要将所有的字段通过表名.字段名
列举出来,当然如果保证所有的字段都不同名,直接*
也可以。
可见这样写sql比较麻烦,如果放到go里面就更臃肿了。
err = MasterDB.SQL("select * from (select financial_flow.id as fid ,financial_flow.number as number,financial_flow.customer_id as customer_id,financial_flow.customer_name as customer_name,financial_flow.type,financial_flow.recharge_way as recharge_way,financial_flow.money,financial_flow.operator_id as operator_id, order_item.id,order_item.order_id,order_item.product_name,order_item.product_id,order_item.product_area_id,order_item.card_type,order_item.card_num,order_item.container_name ,order_item.container_id,order_item.container_state,order_item.using_cpu,order_item.using_ram,order_item.video_memory,order_item.free_data_disk,order_item.expand_data_disk,order_item.max_cuda_version from order_item LEFT JOIN financial_flow on financial_flow.number = order_item.order_id ) as a RIGHT JOIN order_main on a.order_id = order_main.id limit ?,?", paginator.curPage, paginator.perPage).Find(&result)
代码会变成这样,可读性和可维护性都很差:
由于数据库的限制,所有数据只能以二维表的格式展示,因此没有层次结构,没有层次结构,不便于阅读。然而,程序中的数据结构是多样的、层次化的。例如,Go的结构可以很好地与数据库的数据连接。
xorm 中使用结构来表达连接关系。一个结构就是一个表,有多少个连接的表就有多少个兄弟结构。
官网案例:
//结构体1
type Group struct {
Id int64
Name string
}
//结构体2
type User struct {
Id int64
Name string
GroupId int64 `xorm:"index"`
}
数据库表是用户表,组表包含结构字段。如果连接查询sql为:
select group.id as gid,group.name as gname,user.id as uid , user.name as uname,user.group_id as group_id from group LEFT JOIN user on group.id = user.group_id
由于两个表同名了很多字段,因此还需要使用as
重命名,这样在查询的过程中有需要一个新的结构体赋值。显然这样是很不方便的。
Xorm根据结构体特点设计了一种新的赋值方式,将结构体进行嵌套,即使名称属于不同的结构体也不会发生冲突。
type UserGroup struct {
User `xorm:"extends"`
Group `xorm:"extends"`
}
使用嵌套表示连接查询的结果,必须使用xorm的tag并有
extends
关键字。
xorm提供了Join
方法实现连接,其有三个参数engine.Table("user").Join("INNER", "group", "group.id = user.group_id")
第一个参数为连接类型,第二个参数为连接表,第三个参数为on
的条件。而且Join的返回值还是engine仍是过程量,可通过Get
或者Find
方法查询结果。
users := make([]UserGroupType, 0)
engine.Table("user").Join("INNER", "group", "group.id = user.group_id").
Join("INNER", "type", "type.id = user.type_id").
Find(&users)
同时,在使用Join时,还可以使用Where和Find的第二个参数作为条件。 Find的第二个参数还允许使用各种bean作为条件。 where可以是各个表的条件,Find的第二个参数只是相关表的条件。
案件:
type Order2GpuServer struct {
OrderMain `xorm:"extends"`
OrderItem `xorm:"extends"`
Product `xorm:"extends"`
Node `xorm:"extends"`
}
//订单对象
var order2GpuServers []models.Order2GpuServer
session := MasterDB.Join("LEFT", "order_item", "order_main.id = order_item.order_id")
session = session.Join("LEFT", "product", "order_item.product_id = product.id")
session = session.Join("LEFT", "node", "product.node_id = node.id")
session.Find(&order2GpuServers)
调试时可以看到连接查询中的所有表都被分配到相应的结构体中:
XORM通过结构将SQL查询的结果转换为层次结构数据,使数据更加具有层次性。并不是所有的数据都以二维表格的形式展示,而且在程序中赋值也方便。
虽然xorm框架在程序中以结构体i的形式保存了中间量的数据,但是当持久化和离开程序时,数据会变成二维的形式,即全部显示在一起,这样如果有是同名的名字,就会产生冲突,xorm策略不会显示同名的字段。
如下直接序列化返回JSON字符时,不会显示同名字符。应该是不显示同名的字符:
如果需要显示,则需要创建一个新的结构体,并通过连接返回的结构体依次赋值:
这样通过结构体.字段名
来来获取不同个字段的值。
Join("","","")
改变查询的方式为第一个参数LEFT
,RIGHT
,INNER
,OUTER
.