Qt QSqlQueryModel详解

背景知识:

Qt SQL的API分为不同层:

  1. 驱动层 

 驱动层  对于QT是基于C++来实现的框架,该层主要包括QSqlDriver、QSqlDriverCreator、QSqlDriverCreatorbase、QSqlDriverPlugin and QSqlResult。这一层提供了特定数据库和SQL API层之间的底层桥梁。

  1. SQL API层

SQL API层  对于SQL API 层提供了数据库的访问相关类,其中,QSqlDataBase类进行连接,QSqlQuery完成数据库的交互。除此之外,还有QSqlError、QSqlField、QSqlIndex and QSqlRecord类。

  1. 用户接口层

用户接口层  用户接口层的几个类实现将数据库中的数据链接到窗口部件上,这些类是使用模型/视图框架实现的,他们是更高层次的抽象,主要包括QSqlQureyModel,QSqlTableModel and QSqlRelationalTableModel。

用户接口层的类使用模型/视图框架实现了将数据库中的数据链接到窗口控件上

QTableView是常用的内容显示视图组件。数据模型类有:QSqlQueryModel 、QSqlTableModel 、QSqlRelationalTableModel

QSqlQueryModel :通过设置SELECT语句查询获取内容,Model数据是只读的,不能进行编辑

QSqlTableModel : 直接设置一个数据表的名称,可以获取数据表的全部记录,结果是可编辑的。

QSqlRelationalTableModel: 编辑一个数据表,将代码字段通过关系与代码表关联,将代码字段的编辑转换为直观的内容选择编辑。

QSqlQueryModel

QSqlQueryModel :QSqlQueryModel是QSqlTableModel的父类。通过设置SELECT语句查询获取内容,Model数据是只读的,不能进行编辑。意味着不能再如tableview进行编辑修改数据,也不会有代理出现。

所以需要结合QSqlQuery一起使用。

那如果想编辑修改,只能通过弹出一个对话框的,添加控件的方式进行修改,再结合QSqlQuery操作。

  1. tableview显示数据,即对模型设置。那调用setQuery函数即可。
  2. 修改某条数据,把tableview的数据传到对话框,有2种办法。第一种:直接获取模型某行的数据(调用record函数),第二种:通过QSqlQuery执行sql查询语句。然后把修改后的数据通过QSqlQuery语句更新到数据库,数据模型再重新查询语句(调用QSqlQueryModel 类的query().exec()因为前面执行过一次查询或者setQuery),则会自动更新到tableview.

常用的api函数

//清除数据模型,释放所有获得的数据

virtual void clear();

//返回当前关联的QSqlQuery()对象

QSqlQuery query() const;

//设置一个QSqlQuery对象,获取数据

void setQuery(const QSqlQuery &query);

void setQuery(const QString &queryconst QSqlDatabase &db = QSqlDatabase());

//返回一个空记录,包含当前查询的字段信息

QSqlRecord record() const;

 //返回行号为row的记录

QSqlRecord record(int rowconst;

QSqlQuery

执行任意的SQL语句,直接和数据库打交道,可进行insert、delete、update等操作

优点:

  1. 完全自由编写和执行sql语句,可做任意的查询和操作
  2. 性能高,可直接操作数据库结构
  3. 支持事务

缺点:

  1. 需要自行处理结果集,较复杂
  2. 不支持直接编辑。需要自行在程序中处理添加、修改和删除。

//绑定sql语句

bool prepare(const QStringquery);

void bindValue(const QStringplaceholderconst QVariantval,

                   QSql::ParamType type = QSql::In);

void bindValue(int posconst QVariantvalQSql::ParamType type = QSql::In);

void addBindValue(const QVariantvalQSql::ParamType type = QSql::In);

//执行sql语句

bool exec();

bool exec(const QStringquery);

//执行sql语句后,结果的遍历

bool next();

bool previous();

bool first();

bool last();

//某条数据的字段的值

QVariant value(int iconst;

QVariant value(const QStringnameconst;

例如

    QSqlQuery query = QSqlQuery(db);

query.clear();

bool ret = query.prepare("select * from User WHERE userId=?");

    query.bindValue(0,strid);

    bool ok = query.exec();

    while(query.next())//每一行的数据

    {

        QString qvalue = query.value("userId").toString();

        QString qvalue1 = query.value("username").toString();

        qDebug() << qvalue << qvalue1 <<endl;

    }

//执行sql语句后,当前位置的结果,位置由bool next();bool previous();

bool first();bool last();决定。从而知道是某行的数据

QSqlRecord record() const;

//执行sql语句

void setQuery(const QSqlQuery &query);

void setQuery(const QString &queryconst QSqlDatabase &db = QSqlDatabase());

//返回当前关联的QSqlQuery 对象

QSqlQuery query() const;

不带参数:QSqlQuery query = QSqlQuery(db);query.clear();bool ret = query.exec("CREATE TABLE User ( userId VARCHAR(20) PRIMARY KEY, username VARCHAR(20) )");
query.clear();带参数:QSqlQuery query = QSqlQuery(db);bool bret = false;query.clear();bret = query.prepare("insert into User (userId,username) values (?,?)");query.addBindValue(strid);query.addBindValue(strname);bret = query.exec();
query.clear();
或者QSqlQuery query = QSqlQuery(db);query.clear();query.prepare("delete from User WHERE userId=?");query.bindValue(0,strid);bool ok = query.exec();query.clear();

例子

  1. 数据库使用SQLite数据库,格式为.db3
  2. 模型使用QSqlQueryModel ,视图使用QTableView

打开数据库

void MainWindow::on_actOpenDB_triggered()
{QString aFile=QFileDialog::getOpenFileName(this,"选择数据库文件","","SQL Lite数据库(*.db *.db3)");if (aFile.isEmpty())return;//打开数据库DB=QSqlDatabase::addDatabase("QSQLITE"); //添加 SQL LITE数据库驱动DB.setDatabaseName(aFile); //设置数据库名称if (!DB.open())   //打开数据库{QMessageBox::warning(this, "错误", "打开数据库失败",QMessageBox::Ok,QMessageBox::NoButton);return;}//打开数据表openTable();
}

打开数据表,查询数据表的数据到模型

void MainWindow::openTable()
{//打开数据表qryModel=new QSqlQueryModel(this);theSelection=new QItemSelectionModel(qryModel);qryModel->setQuery("SELECT empNo, Name, Gender, Height, Birthday, Mobile, Province, City, Department, "" Education, Salary FROM employee order by empNo");if (qryModel->lastError().isValid()){QMessageBox::information(this, "错误", "数据表查询错误,错误信息\n"+qryModel->lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);return;}qryModel->setHeaderData(0,Qt::Horizontal,"工号");qryModel->setHeaderData(1,Qt::Horizontal,"姓名");qryModel->setHeaderData(2,Qt::Horizontal,"性别");qryModel->setHeaderData(3,Qt::Horizontal,"身高");qryModel->setHeaderData(4,Qt::Horizontal,"出生日期");qryModel->setHeaderData(5,Qt::Horizontal,"手机");qryModel->setHeaderData(6,Qt::Horizontal,"省份");qryModel->setHeaderData(7,Qt::Horizontal,"城市");qryModel->setHeaderData(8,Qt::Horizontal,"部门");qryModel->setHeaderData(9,Qt::Horizontal,"学历");qryModel->setHeaderData(10,Qt::Horizontal,"工资");ui->tableView->setModel(qryModel);ui->tableView->setSelectionModel(theSelection);
//    ui->tableView->resizeColumnsToContents();
//    ui->tableView->horizontalHeader()->setStretchLastSection(true);选择行变化时
//    connect(theSelection,SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
//            this,SLOT(on_currentRowChanged(QModelIndex,QModelIndex)));ui->actOpenDB->setEnabled(false);ui->actRecInsert->setEnabled(true);ui->actRecDelete->setEnabled(true);ui->actRecEdit->setEnabled(true);ui->actScan->setEnabled(true);
}

添加数据,先使用QSqlQuery 添加到数据库,再从数据库查询到model,最后显示到view

void MainWindow::on_actRecInsert_triggered()
{//插入记录
//    QModelIndex curIndex=theSelection->currentIndex();//获取当前选择单元格的模型索引
//    int curRecNo=theSelection->currentIndex().row();//    QSqlRecord  curRec=qryModel->record(curRecNo); //获取当前记录
//    int empNo=curRec.value("EmpNo").toInt();QSqlQuery query;query.exec("select * from employee where EmpNo =-1"); //实际不查询出记录,只查询字段信息
//    query.prepare("select * from employee where EmpNo = :ID");
//    query.bindValue(":ID",empNo);
//    query.exec();
//    query.first();//    if (!query.isValid())
//        return;QSqlRecord curRec=query.record();//获取当前记录,实际为空记录curRec.setValue("EmpNo",qryModel->rowCount()+3000);WDialogData    *dataDialog=new WDialogData(this);Qt::WindowFlags    flags=dataDialog->windowFlags();dataDialog->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); //设置对话框固定大小dataDialog->setInsertRecord(curRec); //插入记录int ret=dataDialog->exec();// 以模态方式显示对话框if (ret==QDialog::Accepted) //OK键被按下{QSqlRecord  recData=dataDialog->getRecordData();query.prepare("INSERT INTO employee (EmpNo,Name,Gender,Height,Birthday,Mobile,Province,"" City,Department,Education,Salary,Memo,Photo) "" VALUES(:EmpNo,:Name, :Gender,:Height,:Birthday,:Mobile,:Province,"" :City,:Department,:Education,:Salary,:Memo,:Photo)");query.bindValue(":EmpNo",recData.value("EmpNo"));query.bindValue(":Name",recData.value("Name"));query.bindValue(":Gender",recData.value("Gender"));query.bindValue(":Height",recData.value("Height"));query.bindValue(":Birthday",recData.value("Birthday"));query.bindValue(":Mobile",recData.value("Mobile"));query.bindValue(":Province",recData.value("Province"));query.bindValue(":City",recData.value("City"));query.bindValue(":Department",recData.value("Department"));query.bindValue(":Education",recData.value("Education"));query.bindValue(":Salary",recData.value("Salary"));query.bindValue(":Memo",recData.value("Memo"));query.bindValue(":Photo",recData.value("Photo"));if (!query.exec())QMessageBox::critical(this, "错误", "插入记录错误\n"+query.lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);else //插入,删除记录后需要重新设置SQL语句查询
//            qryModel->setQuery("SELECT empNo, Name, Gender, Height, Birthday, Mobile, Province, City,"
//                               "Department,Education, Salary FROM employee order by empNo"); //设置数据表qryModel->query().exec();//数据模型重新查询数据,更新tableView显示}delete dataDialog;
}

删除数据

void MainWindow::on_actRecDelete_triggered()
{//删除当前记录int curRecNo=theSelection->currentIndex().row();QSqlRecord  curRec=qryModel->record(curRecNo); //获取当前记录if (curRec.isEmpty()) //当前为空记录return;int empNo=curRec.value("EmpNo").toInt();//获取员工编号QSqlQuery query;query.prepare("delete  from employee where EmpNo = :ID");query.bindValue(":ID",empNo);if (!query.exec())QMessageBox::critical(this, "错误", "删除记录出现错误\n"+query.lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);else //插入,删除记录后需要重新设置SQL语句查询qryModel->query().exec();ui->tableView->update();
//    qryModel->setQuery("SELECT empNo, Name, Gender, Height, Birthday, Mobile, Province, City,"
//                           "Department,Education, Salary FROM employee order by empNo"); //设置数据表
}

修改数据

void MainWindow::on_actRecEdit_triggered()
{//编辑当前记录
//    QModelIndex curIndex=theSelection->currentIndex();//获取当前选择单元格的模型索引int curRecNo=theSelection->currentIndex().row();updateRecord(curRecNo);
}void MainWindow::updateRecord(int recNo)
{ //更新一条记录QSqlRecord  curRec=qryModel->record(recNo); //获取当前记录int empNo=curRec.value("EmpNo").toInt();//获取EmpNoQSqlQuery query; //查询出当前记录的所有字段query.prepare("select * from employee where EmpNo = :ID");query.bindValue(":ID",empNo);query.exec();query.first();if (!query.isValid()) //是否为有效记录return;curRec=query.record();//获取当前记录的数据WDialogData    *dataDialog=new WDialogData(this); //创建对话框Qt::WindowFlags    flags=dataDialog->windowFlags();dataDialog->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); //设置对话框固定大小dataDialog->setUpdateRecord(curRec);//调用对话框函数更新数据和界面int ret=dataDialog->exec();// 以模态方式显示对话框if (ret==QDialog::Accepted) //OK键被按下{QSqlRecord  recData=dataDialog->getRecordData(); //获得对话框返回的记录query.prepare("update employee set Name=:Name, Gender=:Gender,Height=:Height,"" Birthday=:Birthday, Mobile=:Mobile, Province=:Province,"" City=:City, Department=:Department, Education=:Education,"" Salary=:Salary, Memo=:Memo, Photo=:Photo "" where EmpNo = :ID");query.bindValue(":Name",recData.value("Name"));query.bindValue(":Gender",recData.value("Gender"));query.bindValue(":Height",recData.value("Height"));query.bindValue(":Birthday",recData.value("Birthday"));query.bindValue(":Mobile",recData.value("Mobile"));query.bindValue(":Province",recData.value("Province"));query.bindValue(":City",recData.value("City"));query.bindValue(":Department",recData.value("Department"));query.bindValue(":Education",recData.value("Education"));query.bindValue(":Salary",recData.value("Salary"));query.bindValue(":Memo",recData.value("Memo"));query.bindValue(":Photo",recData.value("Photo"));query.bindValue(":ID",empNo);if (!query.exec())QMessageBox::critical(this, "错误", "记录更新错误\n"+query.lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);elseqryModel->query().exec();//数据模型重新查询数据,更新}delete dataDialog;
}

查询数据

查询数据,直接调用setQuery函数即可,这样view只显示查询的字段
void MainWindow::on_actScan_triggered()
{qryModel->setQuery("select empNo, Name from employee where empNo='1001'");
}
或者是好像属于执行了2次查询了
void MainWindow::on_actScan_triggered()
{QSqlQuery qryEmpList(DB); //员工工资信息列表bool bok = qryEmpList.prepare("SELECT empNo, Name, Gender FROM employee where empNo=?");qryEmpList.bindValue(0,"1001");bok = qryEmpList.exec();//这步必须执行,qryModel->setQuery(qryEmpList);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/1774.html

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

相关文章

Servlet(下篇)

哥几个来学 Servlet 啦 ~~ 这个是 Servlet&#xff08;上篇&#xff09;的链接&#xff0c; (2条消息) Servlet &#xff08;上篇&#xff09;_小枫 ~的博客-CSDN博客https://blog.csdn.net/m0_64247824/article/details/131229873主要讲了 Servlet的定义、Servlet的部署方式、…

C语言-基础语法学习-3 二级指针

目录 二级指针二级指针的定义和声明二级指针的初始化二级指针的使用二级指针和函数参数二级指针和动态内存分配数组指针二维数组二维数组的初始化二维数组与指针二维数组的遍历 二级指针 当涉及到多级指针时&#xff0c;C语言的灵活性和强大的指针功能可以得到充分的发挥。二级…

原生HTML+CSS+JS制作自己的导航主页

如果你想使用原生HTML、CSS和JS制作自己的导航主页&#xff0c;你可以按照以下步骤进行操作&#xff1a; 先看效果图&#xff1a; 创建HTML文件&#xff1a;首先&#xff0c;创建一个新的HTML文件&#xff0c;并在文件中添加基本的HTML结构。你可以使用<!DOCTYPE html>…

R语言复现一篇6分的孟德尔随机化文章

上一期我们对孟德尔随机化做了一个简单的介绍&#xff0c;今天我们来复现一篇6分左右的使用了孟德尔随机化方法的文章&#xff0c;文章的题目是&#xff1a;Mendelian randomization analysis does not reveal a causal influence of mental diseases on osteoporosis&#xff…

基于tensorflow深度学习的猫狗分类识别

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

排序算法——归并排序(递归与非递归)

归并排序 以升序为例 文章目录 归并排序基本思想核心步骤递归写法实现代码 非递归处理边界情况实现代码 时间复杂度 基本思想 归并排序是建立在归并操作上的一种有效的排序算法&#xff0c;该算法是采用分治法的一个非常典型的应用&#xff1a;将已有序的子序列合并&#xff…

《C++ Primer》--学习7

顺序容器 容器库概览 迭代器 与容器一样&#xff0c;迭代器有着公共的接口&#xff1a;如果一个迭代器提供某个操作&#xff0c;那么所有提供相同操作的迭代器对这个操作的实现方式都是相同的。 迭代器范围 一个迭代器范围是由一对迭代器表示&#xff0c;两个迭代器分别指向…

IM即时通讯APP在聊天场景中的应用

即时通讯&#xff08;IM&#xff09;应用可以满足人们随时随地进行文字、语音、图片、视频等多媒体信息的传递需求&#xff0c;为个人和企业提供了高效、便捷的沟通方式。在企业中&#xff0c;IM即时通讯APP更是发挥着重要的作用&#xff0c;促进了协作和团队工作的效率提升。以…

项目——学生信息管理系统3

目录 班级添加的界面实现 创建班级的实体类 在org.xingyun.dao 包下 编写 ClassDao 创建 AddStudentClassFrm 添加班级页面 注意创建成 JInternalFrame 类型 给控件起个名字 注释掉main方法 给提交按钮绑定事件 回到 MainFrm.java 给添加班级按钮绑定事件 启动测试 班…

基于卡尔曼滤波进行四旋翼动力学建模(SimulinkMatlab)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

网络安全实战植入后门程序

在 VMware 上建立两个虚拟机&#xff1a;win7 和 kali。 Kali&#xff1a;它是 Linux 发行版的操作系统&#xff0c;它拥有超过 300 个渗透测试工具&#xff0c;就不用自己再去找安装包&#xff0c;去安装到我们自己的电脑上了&#xff0c;毕竟自己从网上找到&#xff0c;也不…

通俗易懂,十分钟读懂DES,详解DES加密算法原理,DES攻击手段以及3DES原理。Python DES实现源码

文章目录 1、什么是DES2、DES的基本概念3、DES的加密流程4、DES算法步骤详解4.1 初始置换(Initial Permutation&#xff0c;IP置换)4.2 加密轮次4.3 F轮函数4.3.1 拓展R到48位4.3.2 子密钥K的生成4.3.3 当前轮次的子密钥与拓展的48位R进行异或运算4.3.4 S盒替换&#xff08;Sub…