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

QT数据库(四):QSqlRelationalTableModel 类

关系数据库概念

例如下列departments、majors、studInfo 这 3 个数据表之间存在关系。

主键与外键

标记“**”的是主键字段,标记“*”的是外键字段。主键字段是一个数据表中表示记录唯一性的字段,例如 studInfo 数据表中的 studID 字段。外键字段是与其他数据表的主键存在关系的字段。

studInfo 数据表中的 departID 字段就是外键字段,它与 departments 数据表中的 departID 字段存在关系。studInfo 数据表中的 departID 存储的是编码,编码的含义需要查询departments 数据表中具有相同 departID 值的一条记录中的 department 字段才可知道。

编码与含义

studInfo 数据表中的 departID 和 majorID 字段一般称为编码字段,departments 数据表和 majors 数据表一般称为编码表。编码表的一条记录有编码字段和编码含义字段,例如 departments 数据表 中,departID 是编码字段,department 是编码含义字段。

在数据库设计中经常采用编码字段和编码表,一是可以减少数据表存储的数据量,例如在studInfo 数据表中不用存储每个学院的全名,而只需存储学院的编码;二是便于修改,例如如果某个学院的名称改变了,那么只需修改 departments 数据表中的一条记录。

主从关系

具有外键关联的两个数据表构成主从关系,主表中的一条记录关联从表中的多条记录。例如, departments 数据表是主表,studInfo 数据表是从表,通过 departments 数据表中一条记录的departID值可以查询出 studInfo 数据表中的多条记录。在删除departments表中的某个学院后,studInfo 表中隶属于该学院的记录也将会被删除。这种方式更新、修改删除都比较方便。

QSqlRelationalTableModel介绍

QSqlRelationalTableModel 是 QSqlTableModel 的子类,它可以作为关系数据表的模型类。

创建对象和设置数据表

QSqlRelationalTableModel 只有一种构造函数,其函数原型定义如下:

QSqlRelationalTableModel(QObject *parent = nullptr, const QSqlDatabase &db=QSqlDatabase())

在创建 QSqlRelationalTableModel 对象时,如果不指定参数 db 的值,就使用应用程序默认的

数据库连接。

创建数据库连接后,用函数 setTable()设置数据表:

tabModel= new QSqlRelationalTableModel(this);

tabModel->setTable("studInfo"); //设置数据表

设置外键关系

关键函数是 setRelation(),该函数原型定义如下:

void QSqlRelationalTableModel::setRelation(int column, const QSqlRelation &relation)

其中,参数 column 是外键字段的字段序号,例如 studInfo 数据表中 departID 字段的序号是 3;参 数 relation 是一个 QSqlRelation 类型的变量,用于表示外键字段关联的编码表、编码字段、编含义字段等信息。

QSqlRelation 类的构造函数原型定义如下:

QSqlRelation(const QString &tableName, const QString &indexColumn, const QString &displayColumn)

其中,tableName 是编码表名称,indexColumn 是外键字段名称,displayColumn 是编码表中代码含义字段的名称。

当使用函数 setRelation()为一个外键字段设置关系时,QSqlRelationalTableModel 内部实际上会创建一个 QSqlTableModel 对象作为编码表的数据模型。

示例程序解读

设置数据表关系

在打开数据表时,创建一个QSqlRelationalTableModel并连接到DB数据库,设置模型的数据表为studInfo,编辑策略为OnManualSubmit(需要手动调用submitAll来更新到数据库)。

void MainWindow::on_actOpenDB_triggered()
{QString aFile=QFileDialog::getOpenFileName(this,"选择文件","","SQLite数据库(*.db3)");if (aFile.isEmpty())return;//打开数据库DB=QSqlDatabase::addDatabase("QSQLITE"); //添加SQLITE数据库驱动DB.setDatabaseName(aFile);      //设置数据库名称//    DB.setHostName();//    DB.setUserName();//    DB.setPassword();if (DB.open())openTable();    //打开数据表elseQMessageBox::warning(this, "错误", "打开数据库失败");
}//打开数据表
void MainWindow::openTable()
{tabModel=new QSqlRelationalTableModel(this,DB);tabModel->setTable("studInfo");     //设置数据表tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit);  //编辑策略tabModel->setSort(tabModel->fieldIndex("studID"),Qt::AscendingOrder);selModel=new QItemSelectionModel(tabModel,this);     //创建选择模型connect(selModel,&QItemSelectionModel::currentChanged,this, &MainWindow::do_currentChanged);
//    connect(selModel,SIGNAL(currentChanged(QModelIndex,QModelIndex)),
//            this,SLOT(do_currentChanged(QModelIndex,QModelIndex)));ui->tableView->setModel(tabModel);ui->tableView->setSelectionModel(selModel);tabModel->setHeaderData(tabModel->fieldIndex("studID"),  Qt::Horizontal, "学号");tabModel->setHeaderData(tabModel->fieldIndex("name"),    Qt::Horizontal, "姓名");tabModel->setHeaderData(tabModel->fieldIndex("gender"),  Qt::Horizontal, "性别");tabModel->setHeaderData(tabModel->fieldIndex("departID"),Qt::Horizontal, "学院");tabModel->setHeaderData(tabModel->fieldIndex("majorID"), Qt::Horizontal, "专业");//设置代码字段的关系tabModel->setRelation(tabModel->fieldIndex("departID"),QSqlRelation("departments","departID","department")); //学院tabModel->setRelation(tabModel->fieldIndex("majorID"),QSqlRelation("majors","majorID","major"));            //专业ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView));  //为关系型字段设置默认代理组件
//    ui->tableView->setItemDelegateForColumn(tabModel->fieldIndex("departID"),
//                                            new QSqlRelationalDelegate(ui->tableView)); //为关系型字段设置缺省代理组件// ui->tableView->setItemDelegateForColumn(tabModel->fieldIndex("majorID"),//                                new QSqlRelationalDelegate(ui->tableView)); //为关系型字段设置缺省代理组件tabModel->select(); //查询数据表的数据ui->actOpenDB->setEnabled(false);ui->actRecAppend->setEnabled(true);ui->actRecInsert->setEnabled(true);ui->actRecDelete->setEnabled(true);ui->actFields->setEnabled(true);
}

示例代码中,有两个点比较关键

1、设置外键字段的关系

    tabModel->setRelation(tabModel->fieldIndex("departID"),QSqlRelation("departments","departID","department")); //学院tabModel->setRelation(tabModel->fieldIndex("majorID"),QSqlRelation("majors","majorID","major"));            //专业

将studInfo数据表中departID外键字段设置为另一个编码表departments对应的字段,并设置字段的含义为编码表中department字段。这样在显示studInfo表中departID时,会自动映射到departments编码表中的department字段。

2、设置代理组件

ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView));

设置后,假设在 tableView 中编辑“学院”和“专业”两个字段的数据时,就会出现一个下拉列表框,

下拉列表内容就是编码表中编码含义字段的所有记录的数据。

添加插入删除记录

这个不用多讲,可查看往期博客

void MainWindow::on_actRecAppend_triggered()
{//添加记录tabModel->insertRow(tabModel->rowCount(),QModelIndex());    //在末尾添加一行QModelIndex curIndex=tabModel->index(tabModel->rowCount()-1,1);selModel->clearSelection();     //清空选择项selModel->setCurrentIndex(curIndex,QItemSelectionModel::Select); //设置当前行
}void MainWindow::on_actRecInsert_triggered()
{//插入记录QModelIndex curIndex=ui->tableView->currentIndex(); //当前行的模型索引tabModel->insertRow(curIndex.row(),QModelIndex());selModel->clearSelection();selModel->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}void MainWindow::on_actRecDelete_triggered()
{//删除当前行tabModel->removeRow(selModel->currentIndex().row());tabModel->submitAll();      //立即提交修改
}

保存和取消

在打开连接数据库后,设置的OnManualSubmit,因此界面的改变想要更新到数据库,需要手动调用submitAll()或者revertAll()来保存或撤销。submitAll()将界面的更改更新到数据库中,revertAll()将界面的更改撤销,也就是重新读取之前数据库中的数据还原界面组件的显示。


void MainWindow::on_actSubmit_triggered()
{//保存修改bool res=tabModel->submitAll();if (!res)QMessageBox::information(this, "消息", "数据保存错误,错误信息\n"+tabModel->lastError().text());else{ui->actSubmit->setEnabled(false);ui->actRevert->setEnabled(false);}
}void MainWindow::on_actRevert_triggered()
{//取消修改tabModel->revertAll();ui->actSubmit->setEnabled(false);ui->actRevert->setEnabled(false);
}

相关文章:

QT数据库(四):QSqlRelationalTableModel 类

关系数据库概念 例如下列departments、majors、studInfo 这 3 个数据表之间存在关系。 主键与外键 标记“**”的是主键字段,标记“*”的是外键字段。主键字段是一个数据表中表示记录唯一性的字段,例如 studInfo 数据表中的 studID 字段。外键字段是与其…...

蓝桥杯刷题——day5

蓝桥杯刷题——day5 题目一题干解题思路一代码解题思路二代码 题目二题干解题思路代码 题目一 题干 给定n个整数 a1,a2,⋯ ,an,求它们两两相乘再相加的和,即: 示例一: 输入: 4 1 3 6 9 输出: 117 题目链…...

YOLO11改进-模块-引入多尺度差异融合模块MDFM

遥感变化检测(RSCD)专注于识别在不同时间获取的两幅遥感图像之间发生变化的区域。近年来,卷积神经网络(CNN)在具有挑战性的 RSCD 任务中展现出了良好的效果。然而,这些方法未能有效地融合双时相特征&#x…...

vlan和vlanif

文章目录 1、为什么会有vlan的存在2、vlan(虚拟局域网)1、vlan原理1. 为什么这样划分了2、如何实现不同交换机相同的vlan实现互访呢3、最优化的解决方法,vlan不同交换机4、vlan标签和vlan数据帧 5、vlan实现2、基于vlan的划分方式1、基于接口的vlan划分方式2、基于m…...

Apache Kylin最简单的解析、了解

官网:Overview | Apache Kylin 一、Apache Kylin是什么? 由中国团队研发具有浓厚的中国韵味,使用神兽麒麟(kylin)为名 的一个OLAP多维数据分析引擎:(据官方给出的数据) 亚秒级响应&#xff…...

MySQL——连接

一.引入库 我们已经分享了很多通过命令行方式去操作数据库,那么数据库该怎么通过语言去访问呢? 这里分享怎么通过C/C来连接数据库。 首先需要到MySQL官网,下载专门用于C/C连接数据库的库,但是一般不需要再去官网下载。 因为在…...

前端微服务实战:大型应用的拆分与治理

"这个系统已经无法维护了..."周五的架构评审会上,我盯着屏幕上那张错综复杂的依赖关系图发愁。作为一个运行了三年的企业级中后台系统,代码量已经超过 50 万行,构建时间长达 40 分钟,任何修改都可能引发连锁反应。 更让人头疼的是,随着业务的快速发展,不同业务线之间…...

Linux shell的七大功能 --- history

1.直接输入“history” 这个命令可以显示出曾经使用过的命令(最近时间的500条) history 2.“history”命令也可以搭配其他命令一起使用。 例:history | grep "vim",找出所有包含“vim”的记录; 也可以搭配…...

C++ webrtc开发(非原生开发,linux上使用libdatachannel库)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、libdatachannel库的下载和build二、开始使用 1.2.引入库3.开始使用 总结 前言 使用c开发webrtc在互联网上留下的资料甚少,经过我一段时间的探…...

C语言刷题

1. 题目描述 根据给出的三角形3条边a:b.c(a.b,c<100.000)&#xff0c;计算三角形的周长和面积。 输入描述: 一行&#xff0c;三角形3条边(能构成三角形)&#xff0c;中间用一个空格隔开. 输出描述: 一行&#xff0c;三角形周长和面积保留两位小数&#xff0c;中问用一个空…...

LabVIEW实现RFID通信

目录 1、RFID通信原理 2、硬件环境部署 3、程序架构 4、前面板设计 5、程序框图设计 6、测试验证 本专栏以LabVIEW为开发平台,讲解物联网通信组网原理与开发方法,覆盖RS232、TCP、MQTT、蓝牙、Wi-Fi、NB-IoT等协议。 结合实际案例,展示如何利用LabVIEW和常用模块实现物联网系…...

Linux 网络流量控制 - 实现概述

摘要 Linux 提供了一整套丰富的流量控制(traffic control)功能。本文档概述了相应的内核代码设计&#xff0c;描述了其结构&#xff0c;并通过描述一种新的排队策略来说明新元素的添加。 1 引言 最近的Linux内核提供了多种流量控制功能。Alexey Kuznetsov&#xff08;kuznet…...

分布式 令牌桶算法 总结

前言 相关系列 《分布式 & 目录》《分布式 & 令牌桶算法 & 总结》《分布式 & 令牌桶算法 & 问题》 参考文献 《【算法】令牌桶算法》 概述 简介 TBA Token Bucket Algorithm 令牌桶算法是一种流行于网络通信领域的流量控制/频率限制算法。令牌…...

FFMPEG视频转图片

用FFMPEG视频转图片&#xff0c;并且for循环 import os import subprocess# 输入文件夹和输出文件夹路径 input_folder r"I:\xxx" output_base_folder r"D:\xxx\YOLO\data\video" output_subfolder_name "20240609"# 创建输出子文件夹 output…...

docker入门实践---虚拟机环境配置

文章目录 1.检查内核版本2.确定centos7可以上网3.关闭防火墙4.关闭防火墙5.更换阿里云6.安装gcc7.设置镜像仓库&#xff08;阿里云&#xff09;8更新软件包9.安装docket-ce10.启动docker11.普通用户权限设置 1.检查内核版本 2.确定centos7可以上网 3.关闭防火墙 下面的这个表示…...

java要防止重复序列化的问题JSON.toJSONString转义问题

要防止重复序列化的问题JSON.toJSONString(entity) 20241213 10:29 背景&#xff1a; 我在设计业务实现echart图标渲染&#xff0c;业务接口实时性查询耗时很长&#xff0c;为了提高系统可用性和用户体验&#xff0c;采用中间表的方案——即在中间表中存储大JSON。 但是在自测…...

TS的类型守卫、类型约束实践

类型守卫 // 基础类型判断 const arr [30, 50] console.log(typeof arr) // object const set new Set(arr) console.log(typeof set) // object const map new Map() console.log(typeof map) // objectclass Customer {constructor() {}buy(method:string) {console.log(…...

文件转曲,限制PDF文件编辑的最佳方案!

随着数字化进程的推进&#xff0c;PDF文件凭借其多样化的功能和优越的兼容性已经被广泛使用&#xff0c;成为了现代文档交流和存储的重要工具&#xff0c;满足了不同用户和行业的需求。 虽然PDF格式文件的功能很多&#xff0c;常见的比如阅读、编辑、加密、转换、还可用于印刷…...

MySQL系列之数据授权(安全)

导览 前言Q&#xff1a;如何对MySQL数据库进行授权管理一、MySQL的“特权”1. 权限级别2. 权限清单 二、授权操作1. 查看权限2. 分配权限3. 回收权限 结语精彩回放 前言 看过博主上一篇的盆友&#xff0c;可以Get到一个知识点&#xff1a;数据授权&#xff08;eg&#xff1a;g…...

用 Python 实现经典的 2048 游戏:一步步带你打造属于你的小游戏!

用 Python 实现经典的 2048 游戏&#xff1a;一步步带你打造属于你的小游戏&#xff01;&#xff08;结尾附完整代码&#xff09; 简介 2048 是一个简单而又令人上瘾的数字拼图游戏。玩家通过滑动方块使相同数字的方块合并&#xff0c;目标是创造出数字 2048&#xff01;在这篇…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...