Golang中sqlx库的嵌套结构解析
Golang中sqlx库的嵌套结构解析 如何使用 sqlx 库创建嵌套结构。
示例:主从表结构。
1 回复
更多关于Golang中sqlx库的嵌套结构解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Golang中使用sqlx库解析嵌套结构,可以通过结构体标签和sqlx的扩展功能实现。以下是一个主从表结构的示例:
假设有订单(主表)和订单项(从表)的关系:
import (
"github.com/jmoiron/sqlx"
"fmt"
)
// 订单项结构
type OrderItem struct {
ID int `db:"id"`
OrderID int `db:"order_id"`
Product string `db:"product"`
Quantity int `db:"quantity"`
}
// 订单结构(包含订单项切片)
type Order struct {
ID int `db:"id"`
Number string `db:"order_number"`
Items []OrderItem // 嵌套结构
}
// 查询订单及其订单项
func GetOrderWithItems(db *sqlx.DB, orderID int) (*Order, error) {
// 使用sqlx的NamedQuery处理嵌套查询
query := `
SELECT
o.id, o.order_number,
oi.id, oi.order_id, oi.product, oi.quantity
FROM orders o
LEFT JOIN order_items oi ON o.id = oi.order_id
WHERE o.id = :order_id
`
// 创建参数映射
params := map[string]interface{}{
"order_id": orderID,
}
// 执行查询
rows, err := db.NamedQuery(query, params)
if err != nil {
return nil, err
}
defer rows.Close()
// 使用结构体扫描
var order *Order
orderMap := make(map[int]*Order)
for rows.Next() {
var (
oID int
oNumber string
oiID sql.NullInt64
oiOrderID sql.NullInt64
oiProduct sql.NullString
oiQuantity sql.NullInt64
)
// 扫描行数据
err := rows.Scan(&oID, &oNumber, &oiID, &oiOrderID, &oiProduct, &oiQuantity)
if err != nil {
return nil, err
}
// 如果订单尚未在map中,创建新订单
if _, exists := orderMap[oID]; !exists {
order = &Order{
ID: oID,
Number: oNumber,
Items: []OrderItem{},
}
orderMap[oID] = order
} else {
order = orderMap[oID]
}
// 如果有订单项数据,添加到订单中
if oiID.Valid {
item := OrderItem{
ID: int(oiID.Int64),
OrderID: int(oiOrderID.Int64),
Product: oiProduct.String,
Quantity: int(oiQuantity.Int64),
}
order.Items = append(order.Items, item)
}
}
if order == nil {
return nil, fmt.Errorf("order not found")
}
return order, nil
}
// 使用Select直接映射到嵌套结构(需要自定义扫描器)
func GetOrderWithItemsSelect(db *sqlx.DB, orderID int) ([]Order, error) {
type OrderRow struct {
OrderID int `db:"order_id"`
OrderNumber string `db:"order_number"`
ItemID *int `db:"item_id"`
Product *string `db:"product"`
Quantity *int `db:"quantity"`
}
var rows []OrderRow
query := `
SELECT
o.id as order_id,
o.order_number,
oi.id as item_id,
oi.product,
oi.quantity
FROM orders o
LEFT JOIN order_items oi ON o.id = oi.order_id
WHERE o.id = ?
ORDER BY o.id
`
err := db.Select(&rows, query, orderID)
if err != nil {
return nil, err
}
// 手动分组数据
ordersMap := make(map[int]*Order)
for _, row := range rows {
if _, exists := ordersMap[row.OrderID]; !exists {
ordersMap[row.OrderID] = &Order{
ID: row.OrderID,
Number: row.OrderNumber,
Items: []OrderItem{},
}
}
if row.ItemID != nil {
item := OrderItem{
ID: *row.ItemID,
OrderID: row.OrderID,
Product: *row.Product,
Quantity: *row.Quantity,
}
ordersMap[row.OrderID].Items = append(ordersMap[row.OrderID].Items, item)
}
}
// 转换为切片
orders := make([]Order, 0, len(ordersMap))
for _, order := range ordersMap {
orders = append(orders, *order)
}
return orders, nil
}
对于更复杂的嵌套结构,可以使用sqlx的StructScan结合自定义扫描:
// 使用sqlx.In和Rebind处理多记录查询
func GetOrdersWithItems(db *sqlx.DB, orderIDs []int) ([]Order, error) {
query, args, err := sqlx.In(`
SELECT
o.id, o.order_number,
oi.id, oi.order_id, oi.product, oi.quantity
FROM orders o
LEFT JOIN order_items oi ON o.id = oi.order_id
WHERE o.id IN (?)
ORDER BY o.id, oi.id
`, orderIDs)
if err != nil {
return nil, err
}
query = db.Rebind(query)
rows, err := db.Queryx(query, args...)
if err != nil {
return nil, err
}
defer rows.Close()
ordersMap := make(map[int]*Order)
for rows.Next() {
var (
order Order
item OrderItem
)
// 使用结构体扫描
err := rows.Scan(
&order.ID,
&order.Number,
&item.ID,
&item.OrderID,
&item.Product,
&item.Quantity,
)
if err != nil {
return nil, err
}
if _, exists := ordersMap[order.ID]; !exists {
ordersMap[order.ID] = &Order{
ID: order.ID,
Number: order.Number,
Items: []OrderItem{},
}
}
if item.ID != 0 {
ordersMap[order.ID].Items = append(ordersMap[order.ID].Items, item)
}
}
orders := make([]Order, 0, len(ordersMap))
for _, order := range ordersMap {
orders = append(orders, *order)
}
return orders, nil
}
这些示例展示了使用sqlx处理嵌套结构的常见模式,包括JOIN查询、手动分组映射和批量查询处理。

