QtSQL学习笔记(4)- 使用SQL Model类

时间:2022-06-03 12:31:04

除了QSqlQuery,Qt提供了3个高级类用于访问数据库。这些类是QSqlQueryModel、QSqlTableModel和QSqlRelationalTableModel。

QtSQL学习笔记(4)- 使用SQL Model类

这些类是由QAbstractTableModel(继承自QAbstractItemModel)驱动并且它通过一个条目视图类(比如QListView和QTableView)使得表示数据库的数据更加简单。这个详细介绍在“用一个表视图表示数据”一节。

使用这些类的另外一个好处是它使得你的代码能够更容易适用于其他数据源。例如,如果你使用的是QSqlTableModel,之后你打算使用XML文件来替换数据库存储数据,那么这个仅仅是简单地用一个数据模型替换另一个数据模型的问题。

SQL查询模型

QSqlQueryModel提供一个基于SQL查询的只读模型。例如:

 QSqlQueryModel model;
model.setQuery("SELECT * FROM employee"); for (int i = ; i < model.rowCount(); ++i) {
int id = model.record(i).value("id").toInt();
QString name = model.record(i).value("name").toString();
qDebug() << id << name;
}

在使用QSqlQueryModel::setQuery()设置好查询之后,你可以使用QSqlQueryModel::record(int)来访问单个记录。你也可以使用QSqlQueryModel::data()和其他任何继承自QAbstractItemModel的函数。

还有一个重载的setQuery()方法,它带有一个QSqlQuery对象并且在它的结果集中进行操作。它使得你可以使用QSqlQuery的任意特性来设置查询(例如,prepared queries)。

SQL表模型

QSqlTableModel提供一个一次只能对一个SQL表进行操作的可读可写模型。例如:

 QSqlTableModel model;
model.setTable("employee");
model.setFilter("salary > 50000");
model.setSort(, Qt::DescendingOrder);
model.select(); for (int i = ; i < model.rowCount(); ++i) {
QString name = model.record(i).value("name").toString();
int salary = model.record(i).value("salary").toInt();
qDebug() << name << salary;
}

QSqlTableModel是一个高级的可替代QSqlQuery的模型,可以用于浏览和修改单个SQL表。它典型的优点是只需要少量的代码并且不需要了解SQL语法。

使用QSqlTableModel::record()来检索表中的一行,然后使用QSqlTableModel::setRecord()来修改这一行。例如,下面的代码将对所有雇员的薪水增加10%。

 for (int i = ; i < model.rowCount(); ++i) {
QSqlRecord record = model.record(i);
double salary = record.value("salary").toInt();
salary *= 1.1;
record.setValue("salary", salary);
model.setRecord(i, record);
}
model.submitAll();

你也可以使用继承自QAbstractItemModel的方法QSqlTableModel::data()和QSqlTableModel::setData()来修改这些数据。例如,下面的代码展示了怎样用setData()更新一条记录:

 model.setData(model.index(row, column), );
model.submitAll();

下面的代码时怎样插入一行:

 model.insertRows(row, );
model.setData(model.index(row, ), );
model.setData(model.index(row, ), "Peter Gordon");
model.setData(model.index(row, ), );
model.submitAll();

下面的代码时如何删除5条连续行:

 model.removeRows(row, );
model.submitAll();

QSqlTableModel::removeRows()的第一个参数是带删除的第一行的索引号。

当你完成了对记录的修改,你总是需要调用QSqlTableModel::submitAll()来确保这些改动被写入到数据库中。

什么时候以及是否真的需要调用submitAll()实际上取决于表的编辑策略(edit strategy),默认的策略是QSqlTableModel::OnRowChange,也就是说当用户选择了另一个不同的行时上一行的改动将被应用到数据库。其他的策略还包括QSqlTableModel::OnManualSubmit(所有改动将缓存在模型中,直到你调用submitAll()方法)和QSqlTableModel::OnFieldChange (不缓存改动)。这些策略在QSqlTableModel结合一个视图一起使用时相当有用。

QtSQL学习笔记(4)- 使用SQL Model类

SQL关系表模型

QSqlRelationalTableModel扩展了QSqlTableModel来提供了对外键(foreign key)的支持。一个外键是一个表中的一个字段与另一个表中的主键(primary key)字段之间的一一映射。例如,如果一个book表中有一个authorid字段关联到author表中的id字段,那么我们说authorid是一个外键。

QtSQL学习笔记(4)- 使用SQL Model类

The screenshot on the left shows a plain QSqlTableModel in a QTableView. Foreign keys (city and country) aren't resolved to human-readable values. The screenshot on the right shows a QSqlRelationalTableModel, with foreign keys resolved into human-readable text strings.

下面的代码片段展示了如何设置QSqlRelationalTableModel:

 model->setTable("employee");

 model->setRelation(, QSqlRelation("city", "id", "name"));
model->setRelation(, QSqlRelation("country", "id", "name"));

可以查阅QSqlRelationalTableModel文档了解更多内容。