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.ModelOrders []Order
}type Order struct {gorm.ModelUserID  uintProduct 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 mainimport ("fmt""gorm.io/driver/mysql""gorm.io/gorm"
)// User 模型
type User struct {ID    uintName  stringEmail stringOrders []Order // 一个用户有多个订单
}// Order 模型
type Order struct {ID      uintUserID  uintUser    User // 订单属于一个用户Products []Product `gorm:"many2many:order_products;"` // 一个订单有多个产品
}// Product 模型
type Product struct {ID    uintName  stringPrice float64Orders []Order `gorm:"many2many:order_products;"` // 一个产品可以属于多个订单
}// OrderProduct 模型(中间表)
type OrderProduct struct {OrderID   uintProductID uintQuantity  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 []Userdb.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.mzph.cn/diannao/69807.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

协议-LVDS

是什么? LVDS 全称为 Low-Voltage Differential Signaling,低电压差分信号 低功耗、低误码率、低串扰和低辐射的差分信号,采用-350mV~350mV极底的电压摆幅高速差动传输数据,实现点对点或一点对多点的连接 由于电压幅度低&#xf…

dma_ddr 的编写 通过mig控制ddr3

此外还有别的模块 本模块是 其中一个 timescale 1ns/1ps module dma_ctrl (input wire ui_clk , //100MHZ 用户时钟input wire ui_rst_n ,//写fifo的写端口 input wire wf_wr_clk , //由数据产生模块的时…

数据中心网络监控

数据中心是全球协作的特定设备网络,用来在internet网络基础设施上传递、加速、展示、计算、存储数据信息。 对于任何利用IT基础设施的企业来说,数据中心都是运营的核心,它本质上为整个业务网络托管业务应用程序和存储空间。数据中心可以是任…

w~大模型~合集30

我自己的原文哦~ https://blog.51cto.com/whaosoft/13284996 #VideoMamba 视频理解因大量时空冗余和复杂时空依赖,同时克服两个问题难度巨大,CNN 和 Transformer 及 Uniformer 都难以胜任,Mamba 是个好思路,让我们看看本文是…

将Excel中的图片保存下载并导出

目录 效果演示 注意事项 核心代码 有需要将excel中的图片解析出来保存到本地的小伙子们看过来!!! 效果演示 注意事项 仅支持xlsx格式:此方法适用于Office 2007及以上版本的.xlsx文件,旧版.xls格式无法使用。 图片名…

Ansible 主机清单语法

Ansible 主机清单语法 Ansible的hosts配置文件编写方法 配置文件路径:/etc/ansible/hosts 单个清单主机组 [主机名]#组名 ip地址 域名多台连续主机 #域名 www.[001:100].com #从www.001.com-www.100.com#IP地址 192.168.1.[1:100] #从192.168.1.1-192.168.1.10…

自定义sort排序

数组中&#xff0c;根据出现次数以大到小排序&#xff0c;当频率相同时按元素值降序排序 #include <iostream> #include <vector> #include <algorithm> #include <unordered_map>// 全局的 unordered_map 用于存储元素频率 std::unordered_map<in…

如何在 GitHub 上写博客

如何在 GitHub 上写博客并保存 GitHub 是一个强大的平台&#xff0c;不仅用于托管代码&#xff0c;还可以用于写博客。借助 GitHub Pages&#xff0c;你可以免费创建和托管个人博客。通过 GitHub Pages 或静态站点生成工具&#xff08;如 Jekyll、Hugo、Hexo 等&#xff09;&a…

Windows11+PyCharm利用MMSegmentation训练自己的数据集保姆级教程

系统版本&#xff1a;Windows 11 依赖环境&#xff1a;Anaconda3 运行软件&#xff1a;PyCharm 一.环境配置 通过Anaconda Prompt(anaconda)打开终端创建一个虚拟环境 conda create --name mmseg python3.93.激活虚拟环境 conda activate mmseg 4.安装pytorch和cuda tor…

机会病原菌——产气克雷伯菌(Klebsiella aerogenes),产生组胺诱发IBS腹痛

2021年6月份&#xff0c;我们分享过一篇“全面认识——肺炎克雷伯菌(Klebsiella pneumoniae) ”的文章&#xff0c;当时也是发现该菌在肠道的人群检出率较高&#xff0c;基于想全面了解该菌&#xff0c;我们查阅整理了很多资料&#xff0c;包括统计了谷禾健康数据库中肺炎克雷伯…

[SAP ABAP] OOALV 报表练习1(操作讲解)

阅读该篇文章之前可先查看以下2篇文章 [SAP ABAP] ALV报表练习1 [SAP ABAP] 复制ABAP程序 上面我们是使用Function ALV进行报表程序的开发,接下来我们将使用OOALV的方式去进行报表开发,以上面的《ALV报表练习1》的程序进行相关的修改 关于OO ALV报表的选择屏幕以及取数逻…

PlantUML 总结

PlantUML 总结 1. 概述 PlantUML 是一个开源工具&#xff0c;允许用户通过简单的文本描述来生成各种UML图表。它支持多种图表类型&#xff0c;包括但不限于序列图、用例图、类图、活动图等。 2. 基本概念 2.1 开始和结束标记 startuml 和 enduml&#xff1a;用于标记Plant…

后端面试题

以下是一些常见的后端面试题: 一、通用基础 请简述HTTP协议的工作原理。 答案: HTTP是基于请求 - 响应模型的协议。客户端(通常是浏览器)向服务器发送一个HTTP请求,请求包含请求行(包含请求方法,如GET、POST等、请求的URL和HTTP版本)、请求头(包含诸如浏览器类型、接…

Java--集合(理论)上

目录 一、collection collection常用方法 1.List&#xff08;可以存在重复元素&#xff09; 迭代器 迭代器的概念 注意事项 例子 1.ArrayList 特点 2.LinkedLIst 特点 3.Vector 特点 2.Set&#xff08;无重复元素&#xff09; 1.HashSet 特点 2.Linkedhashset&…

在mac中安装Colima使用docker(替代Docker Desktop)

目录 推荐方案&#xff1a;Colima Docker CLI&#xff08;原生 ARM 支持&#xff09; 步骤 1: 安装必需工具 步骤 2: 启动 Colima (优化 ARM 虚拟机) 步骤 3: 绑定 Docker CLI 到 Colima 步骤 4: 验证 Docker 运行 方案对比与注意事项 常见陷阱 卸载残留配置&#xff…

C语言基础13:循环结构 for和while

循环结构 什么是循环结构 代码在满足某种条件的前提下&#xff0c;重复执行&#xff0c;就叫做循环结构。 循环的分类 无限循环&#xff1a;其实就是死循环&#xff0c;程序设计中尽量避免无限循环&#xff0c;如果非要使用&#xff0c;那么这个循环一定要在可控范围内。有…

【核心特性】从鸭子类型到Go的io.Writer设计哲学

在编程语言的设计中&#xff0c;鸭子类型和接口设计是两种非常重要的理念。它们都强调了对象的行为和能力&#xff0c;而非其具体的类型或继承关系。Go 语言的io.Writer 接口是这种设计理念的典型代表&#xff0c;它通过简洁的接口定义&#xff0c;实现了强大的功能和灵活性。 …

C++17 中的 std::gcd:探索最大公约数的现代 C++ 实现

文章目录 一、std::gcd 的基本用法&#xff08;一&#xff09;包含头文件&#xff08;二&#xff09;函数签名&#xff08;三&#xff09;使用示例 二、std::gcd 的实现原理三、std::gcd 的优势&#xff08;一&#xff09;简洁易用&#xff08;二&#xff09;类型安全&#xff…

CMA软件评测机构测量不确定度评定具体怎么做?

测量不确定度作为测量结果的一部分&#xff0c;是评价测量活动质量的重要指标&#xff0c;也是CMA软件评测机构衡量检测结果准确性和可靠性的重要参数。本文为您介绍CMA软件评测机构测量不确定度评定具体应该怎么做。 在申请CMA资质时&#xff0c;软件评测机构需要制定《测量不…

vue项目网页图标修改

参考:https://blog.csdn.net/qq_53911056/article/details/144744699 在Vue项目中修改网页图标&#xff08;favicon&#xff09;是一个相对简单的过程。以下是详细的步骤&#xff1a; 准备新的图标文件 准备一个新的图标文件&#xff08;通常是 .ico 格式&#xff0c;但也支持其…