当前位置: 首页 > article >正文

Golang GORM系列:GORM 高级查询教程

有效的数据检索是任何程序功能的基础。健壮的Go对象关系映射包(称为GORM)除了标准的CRUD操作之外,还提供了复杂的查询功能。这是学习如何使用GORM进行高级查询的综合资源。我们将涵盖WHERE条件、连接、关联、预加载相关数据,甚至涉及原始SQL查询。到最后,你的Go应用程序将具备以无与伦比的精度提取和操作数据的能力。

在这里插入图片描述

GORM where 条件

使用WHERE条件优化查询对于提取特定的数据子集至关重要。

步骤1:基本的WHERE子句

使用GORM的‘ Where ’方法来应用条件:

var expensiveProducts []Product
db.Where("price > ?", 50).Find(&expensiveProducts)

步骤2:AND & OR条件

使用逻辑运算符组合多个条件:

var filteredProducts []Product
db.Where("price > ? AND category = ?", 50, "Electronics").Find(&filteredProducts)

GORM中的连接和关联

模型之间的关联支持跨多个表的复杂查询。

步骤1:定义关联

在你的模型结构中建立关联:

type User struct {
    gorm.Model
    Orders []Order
}

type Order struct {
    gorm.Model
    UserID  uint
    Product string
}

步骤2:执行连接

使用GORM的‘ Joins ’方法从关联的模型中检索数据:

var usersWithOrders []User
db.Joins("JOIN orders ON users.id = orders.user_id").Find(&usersWithOrders)

GORM预加载相关数据

有效地加载相关数据以最小化数据库查询。

步骤1:预加载关联

使用GORM的‘ Preload ’方法来快速加载相关数据:

var users []User
db.Preload("Orders").Find(&users)

步骤2:嵌套预加载

预加载嵌套关联,用于全面的数据检索;

var users []User
db.Preload("Orders.OrderItems").Find(&users)

GORM中的原始SQL查询

对于复杂的查询,GORM允许执行原始SQL语句。

步骤1:原始SQL查询

使用GORM的‘ raw ’方法执行原始SQL查询:

var products []Product
db.Raw("SELECT * FROM products WHERE price > ?", 50).Scan(&products)

步骤2:绑定变量

使用绑定变量进行更安全、更高效的查询:

var categoryName = "Electronics"
var expensivePrice = 100
var filteredProducts []Product
db.Raw("SELECT * FROM products WHERE category = ? AND price > ?", categoryName, expensivePrice).Scan(&filteredProducts)

完整示例

在现实场景中,用户有多个订单,一个订单可能包含多个产品。为了实现这一点,我们需要引入一个中间表(即关联表)来表示订单和产品之间的多对多关系。

数据模型如下

  1. User 模型:表示用户。
  2. Order 模型:表示订单。
  3. Product 模型:表示产品。
  4. OrderProduct 模型:表示订单和产品之间的多对多关系(中间表)。

完整代码

我们通过引入中间表 order_products,实现了订单和产品之间的多对多关系。使用 Preload 方法可以高效地加载嵌套关系,避免多次查询数据库。这个实例展示了如何在 GORM 中处理复杂的多对多关系,并支持一个订单包含多个产品的场景。你可以根据实际需求进一步扩展模型和查询逻辑,例如添加更多的字段或条件。

package main

import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

// User 模型
type User struct {
    ID    uint
    Name  string
    Email string
    Orders []Order // 一个用户有多个订单
}

// Order 模型
type Order struct {
    ID      uint
    UserID  uint
    User    User // 订单属于一个用户
    Products []Product `gorm:"many2many:order_products;"` // 一个订单有多个产品
}

// Product 模型
type Product struct {
    ID    uint
    Name  string
    Price float64
    Orders []Order `gorm:"many2many:order_products;"` // 一个产品可以属于多个订单
}

// OrderProduct 模型(中间表)
type OrderProduct struct {
    OrderID   uint
    ProductID uint
    Quantity  int // 订单中某个产品的数量
}

func main() {
    // 连接数据库
    dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    // 自动迁移模型
    db.AutoMigrate(&User{}, &Order{}, &Product{}, &OrderProduct{})

    // 插入测试数据
    user := User{Name: "John Doe", Email: "john@example.com"}
    db.Create(&user)

    product1 := Product{Name: "Laptop", Price: 1200.00}
    product2 := Product{Name: "Mouse", Price: 25.00}
    db.Create(&product1)
    db.Create(&product2)

    order := Order{UserID: user.ID}
    db.Create(&order)

    // 添加产品到订单
    db.Model(&order).Association("Products").Append([]Product{product1, product2})

    // 查询用户及其订单和产品信息
    var users []User
    db.Preload("Orders.Products").Find(&users)

    // 打印结果
    for _, user := range users {
        fmt.Printf("User: %s, Email: %s\n", user.Name, user.Email)
        for _, order := range user.Orders {
            fmt.Printf("  Order ID: %d\n", order.ID)
            for _, product := range order.Products {
                fmt.Printf("    Product: %s, Price: %.2f\n", product.Name, product.Price)
            }
        }
    }
}
数据模型
  • Order 和 Product 的多对多关系
    • 一个订单可以包含多个产品,一个产品也可以属于多个订单。
    • 使用 gorm:"many2many:order_products;" 标签定义多对多关系,order_products 是中间表的名称。
  • 中间表 OrderProduct
    • 中间表包含 OrderIDProductID 作为外键,以及额外的字段 Quantity 表示订单中某个产品的数量。
查询数据
  • 使用 Preload 方法预加载嵌套关系:
    • Preload("Orders") 加载用户的订单。
    • Preload("Orders.Products") 加载每个订单的产品。
  • 这样可以避免 N+1 查询问题,提高查询效率。
中间表数据
// 添加产品到订单
db.Model(&order).Association("Products").Append([]Product{product1, product2})
  1. Association("Products")
    • 这里使用了 GORM 的 Association 方法,表示操作 Order 模型与 Product 模型之间的多对多关系。
    • ProductsOrder 模型中定义的关联字段。
  2. Append([]Product{product1, product2})
    • Append 方法用于将产品添加到订单中。
    • 这里传入了两个产品:product1product2
  3. 中间表数据的插入
    • 当调用 Append 方法时,GORM 会自动在中间表 order_products 中插入数据。
    • 插入的数据包括:
      • OrderID:当前订单的 ID。
      • ProductID:每个产品的 ID。
      • Quantity:如果中间表有其他字段(如 Quantity),可以通过额外配置插入数据(见下文)。

假设:

  • 订单的 ID 是 1
  • 产品的 ID 分别是 1(Laptop)和 2(Mouse)。

调用 Append 方法后,GORM 会自动在 order_products 表中插入以下数据:

OrderIDProductIDQuantity
110
120

注意:如果中间表有其他字段(如 Quantity),需要额外处理。


如果需要插入 Quantity 字段

如果中间表 OrderProduct 包含 Quantity 字段,并且希望在插入时设置数量,可以通过以下方式实现:

修改后的代码
// 添加产品到订单,并设置数量
orderProduct1 := OrderProduct{OrderID: order.ID, ProductID: product1.ID, Quantity: 1}
orderProduct2 := OrderProduct{OrderID: order.ID, ProductID: product2.ID, Quantity: 2}
db.Create(&orderProduct1)
db.Create(&orderProduct2)
  • 手动创建 OrderProduct 记录,并设置 OrderIDProductIDQuantity
  • 使用 db.Create 将记录插入到 order_products 表中。

最后总结

从Go应用程序获取和修改数据的最全面的工具集是由GORM复杂的查询功能提供的。通过学习如何使用连接和关系、预加载相关数据,甚至尝试原始SQL查询,可以很快掌握精确而复杂地数据查询。这些特性不仅提高了程序的效率,而且还提供了对以前难以想象的复杂数据情况的访问。


http://www.kler.cn/a/543280.html

相关文章:

  • k8s管理工具之lens
  • SQL数据清理:去除字段值中的多余符号(Demo例子)
  • 【通俗易懂说模型】一篇弄懂几个经典CNN图像模型(AlexNet、VGGNet、ResNet)
  • AI+智能中台企业架构设计_重新定义制造(46页PPT)
  • 【图片合并转换PDF】如何将每个文件夹下的图片转化成PDF并合并成一个文件?下面基于C++的方式教你实现
  • Anything llm Token数理解
  • SQL Server 逻辑查询处理阶段及其处理顺序
  • tcp传输协议机制
  • 用php tp6对接钉钉审批流的 table 表格 明细控件 旧版sdk
  • 硬件学习笔记--39 电磁兼容试验-3射频电磁场试验介绍
  • 一、计算机等级考试——标准评分
  • 当Axure遇见DeepSeek:设计工具的革命性进化
  • 视频理解新篇章:Mamba模型的探索与应用
  • Spring中常见的设计模式
  • Flutter PIP 插件 ---- iOS Video Call
  • python基础入门:6.3异常处理机制
  • 鸿蒙HarmonyOS NEXT开发:横竖屏切换开发实践
  • Git与Github远程仓库使用
  • Vue项目能进行哪些性能优化?
  • WPS OFFICE制作多级下拉菜单
  • Java实现模版方法模式
  • LabVIEW无人机飞行状态监测系统
  • 获取 Windows 视频时长的正确方式——Windows Shell API 深度解析
  • Flask Web开发的重要概念和示例
  • 日志2025.2.12
  • OmniManip:以目标为中心的交互基元作为空间约束实现通用机器人操作