首页 Qt 学习之路 2 Qt 学习之路 2(56):使用模型操作数据库

Qt 学习之路 2(56):使用模型操作数据库

14 2.3K

前一章我们使用 SQL 语句完成了对数据库的常规操作,包括简单的 CREATE、SELECT 等语句的使用。我们也提到过,Qt 不仅提供了这种使用 SQL 语句的方式,还提供了一种基于模型的更高级的处理方式。这种基于QSqlTableModel 的模型处理更为高级,如果对 SQL 语句不熟悉,并且不需要很多复杂的查询,这种QSqlTableModel模型基本可以满足一般的需求。本章我们将介绍QSqlTableModel的一般使用,对比 SQL 语句完成对数据库的增删改查等的操作。值得注意的是,QSqlTableModel并不一定非得结合 QListViewQTableView使用,我们完全可以用其作一般性处理。

首先我们来看看如何使用QSqlTableModel 进行 SELECT 操作:

if (connect("demo.db")) {
    QSqlTableModel model;
    model.setTable("student");
    model.setFilter("age > 20 and age < 25");
    if (model.select()) {
        for (int i = 0; i < model.rowCount(); ++i) {
            QSqlRecord record = model.record(i);
            QString name = record.value("name").toString();
            int age = record.value("age").toInt();
            qDebug() << name << ": " << age;
        }
    }
} else {
    return 1;
}

我们依旧使用了前一章的connect()函数。接下来我们创建了QSqlTableModel实例,使用setTable()函数设置所需要操作的表格;setFilter()函数则是添加过滤器,也就是 WHERE 语句所需要的部分。例如上面代码中的操作实际相当于 SQL 语句

SELECT * FROM student WHERE age > 20 and age < 25

使用QSqlTableModel::select()函数进行操作,也就是执行了查询操作。如果查询成功,函数返回 true,由此判断是否发生了错误。如果没有错误,我们使用record()函数取出一行记录,该记录是以QSqlRecord的形式给出的,而QSqlRecord::value()则取出一个列的实际数据值。注意,由于QSqlTableModel没有提供const_iterator遍历器,因此不能使用foreach宏进行遍历。

另外需要注意,由于QSqlTableModel只是一种高级操作,肯定没有实际 SQL 语句方便。具体来说,我们使用QSqlTableModel只能进行 SELECT * 的查询,不能只查询其中某些列的数据。

下面一段代码则显示了如何使用QSqlTableModel进行插入操作:

QSqlTableModel model;
model.setTable("student");
int row = 0;
model.insertRows(row, 1);
model.setData(model.index(row, 1), "Cheng");
model.setData(model.index(row, 2), 24);
model.submitAll();

插入也很简单:model.insertRows(row, 1);说明我们想在索引 0 的位置插入 1 行新的数据。使用setData()函数则开始准备实际需要插入的数据。注意这里我们向 row 的第一个位置写入 Cheng(通过model.index(row, 1),回忆一下,我们把 model 当作一个二维表,这个坐标相当于第 row 行第 1 列),其余以此类推。最后,调用submitAll()函数提交所有修改。这里执行的操作可以用如下 SQL 表示:

INSERT INTO student (name, age) VALUES ('Cheng', 24)

当我们取出了已经存在的数据后,对其进行修改,然后重新写入数据库,即完成了一次更新操作:

QSqlTableModel model;
model.setTable("student");
model.setFilter("age = 25");
if (model.select()) {
    if (model.rowCount() == 1) {
        QSqlRecord record = model.record(0);
        record.setValue("age", 26);
        model.setRecord(0, record);
        model.submitAll();
    }
}

这段代码中,我们首先找到 age = 25 的记录,然后将 age 重新设置为 26,存入相同的位置(在这里都是索引 0 的位置),提交之后完成一次更新。当然,我们也可以类似其它模型一样的设置方式:setData()函数。具体代码片段如下:

if (model.select()) {
    if (model.rowCount() == 1) {
        model.setData(model.index(0, 2), 26);
        model.submitAll();
    }
}

注意我们的 age 列是第 3 列,索引值为 2,因为前面还有 id 和 name 两列。这里的更新操作则可以用如下 SQL 表示:

UPDATE student SET age = 26 WHERE age = 25

删除操作同更新类似:

QSqlTableModel model;
model.setTable("student");
model.setFilter("age = 25");
if (model.select()) {
    if (model.rowCount() == 1) {
        model.removeRows(0, 1);
        model.submitAll();
    }
}

如果使用 SQL 则是:

DELETE FROM student WHERE age = 25

当我们看到removeRows()函数就应该想到:我们可以一次删除多行。事实也正是如此,这里不再赘述。

14 评论

pkgfs 2013年6月30日 - 10:20

😛 使用SQL确实更方便

回复
wangdapao 2015年5月8日 - 23:22

豆子老师,我用qt 连接mysql怎么也连不上,是不是得需要把已经编译好的mysql驱动放到qtsqldriver下,但是为什么还是显示not loaded

回复
彭冲 2015年6月28日 - 19:59

对于QT存在QMYSQL驱动,但是运行连接数据库程序时却提醒”QMYSQL driver not loaded “的问题的就出现的原因和解决的方法:

出现的该问题的首要原因可能是mysql数据库和QT的位数不一致,如果mysql是64位的,而QT编译器时32位的,可能会造成上述的问题,所以在选择安装版本的时候可以,最好是保持二者的一致。

在二者保持一致的前提下将C:\Program Files (x86)\MySQL\MySQL Server 5.5\lib目录下的libmysql.dll复制到C:\Qt\Qt5.3.2\5.3\mingw482_32\bin或Qt\Qt5.3.2\Tools\mingw482_32\bin目录下皆可。

回复
apm123 2016年5月19日 - 21:31

豆子老师我有时候 model.submitAll();执行不了是怎么回事啊

回复
ccppaa 2016年6月6日 - 08:58

#include

class MyStandardModel : public QStandardItemModel
{
Q_OBJECT
public:
MyStandardModel(QObject *parent=NULL) : QStandardItemModel(parent) { }
MyStandardModel(int row, int column, QObject *parent=NULL)
: QStandardItemModel(row, column, parent) { }
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
{
if( Qt::TextAlignmentRole == role )
return Qt::AlignCenter;
return QStandardItemModel::data(index, role);
}

};
请问大神,这些代码的用处是什么

回复
豆子 2016年6月6日 - 09:12

这是MyStandardModel的实现,两个构造函数,一个data()函数,哪里有问题啊?

回复
ccppaa 2016年6月6日 - 09:13

代码没有问题,是想知道这些代码的用处,他的作用是什么

回复
豆子 2016年6月6日 - 14:32

构造函数不用说了,data() 函数就是用来根据具体的角色来显示数据,包括数据的显示格式、颜色之类。例如代码中,如果 role == Qt::TextAlignmentRole,就按照居中显示。这部分数据是由 model 提供的,也就是使用 model 驱动界面的更新,这是模型-视图模式的应用:将视图的更新交给模型,我们只处理模型的数据,不需要关心视图究竟如何更新显示

回复
ccppaa 2016年6月6日 - 16:17

多谢大神

ccppaa 2016年7月19日 - 10:23

QSqlRecord是不是只能取一行数据,如果是要取多行数据,应该怎么处理

回复
豆子 2016年7月19日 - 20:46

QSqlRecord 代表一行数据。多行数据的话,你需要用 QSqlQuery 执行 SELECT 语句,然后用 while(QSqlQuery::next()) 循环取出每一行数据进行处理。你可以看看 QSqlQuery 的文档。

回复
ccppaa 2016年7月20日 - 08:59

谢谢,昨天自己看了文档,这个问题解决了,谢谢你

回复
ben 2017年8月29日 - 11:04

使用QSqlTableModel进行插入操作,虽然操作成功了,但是后台数据表并没有新增一行数据,这可能是什么原因呢?(换了record的方法,也是无法新增,只有用sql语句的方式才可以,搞不明白为什么这样)
代码如下:
QSqlTableModel model;
model.setTable("pole_location");
if(model.select())
{
QMessageBox::about(NULL, "", QString::number(model.rowCount())); //显示正确的行数
int row = model.rowCount() + 1;
model.insertRows(row, 1);
model.setData(model.index(row, 1), row);
model.setData(model.index(row, 2), "p5");
model.setData(model.index(row, 3), 5);
model.setData(model.index(row, 4), 5);
model.setData(model.index(row, 5), 77);
model.setData(model.index(row, 6), 77);
if(model.submitAll())
{
QMessageBox::about(NULL, "", QString::number(model.rowCount())); //会执行此句,说明submitAll()成功了,但是后次数据表并不会新增一条数据
}
}

回复
Wakfu 2018年4月23日 - 09:43

豆子老师,想问个问题:
如果我要插入数据并且修改model需要重载model的flags和setdata函数是么?
在这两个函数中操作数据库是么?

回复

回复 豆子 取消回复

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2