本页内容

使用 SQL 模型类

除了QSqlQuery 之外,Qt还提供了三个用于访问数据库的高级类。这些类分别是QSqlQueryModel 、QSqlTableModel 和QSqlRelationalTableModel 。

QSqlQueryModel基于任意 SQL 查询的只读模型。
QSqlTableModel一个作用于单张表的读写模型。
QSqlRelationalTableModel一个支持外键的 `QSqlTableModel ` 子类。

这些类继承自QAbstractTableModel (该类又继承自QAbstractItemModel ),可轻松地在QListView 和QTableView 等项目视图类中呈现数据库数据。相关内容在“在表格视图中呈现数据”一节中有详细说明。

使用这些类的另一个优势在于,它能让您的代码更易于适应其他数据源。例如,如果您使用QSqlTableModel ,后来决定改用 XML 文件而非数据库来存储数据,那么本质上只需将一个数据模型替换为另一个即可。

SQL 查询模型

QSqlQueryModel 提供了一种基于 SQL 查询的只读模型。

示例:

    QSqlQueryModel model;
    model.setQuery("SELECT * FROM employee");

    for(inti= 0; i<model.rowCount();++i) {
        intid=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 的任何功能来设置查询(例如,预编译查询)。

SQL 表模型

QSqlTableModel 提供了一种读写模型,该模型每次仅处理一张 SQL 表。

示例:

    QSqlTableModel model;
    model.setTable("employee");
    model.setFilter("salary > 50000");
    model.setSort(2,Qt::DescendingOrder);
    model.select();

    for(inti= 0; i<model.rowCount();++i) {
        QString name=model.record(i).value("name").toString();
        intsalary=model.record(i).value("salary").toInt();
        qDebug() << name << salary;
    }

QSqlTableModel 是QSqlQuery 的高级替代方案,用于浏览和修改单个 SQL 表。它通常能减少代码量,且无需了解 SQL 语法。

使用 `QSqlTableModel::record()` 检索表中的一行,使用 `QSqlTableModel::setRecord()` 修改该行。例如,以下代码将每位员工的工资提高 10%:

    for (int i = 0; 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), 75000);
    model.submitAll();

以下是如何插入一行并填充其数据的方法:

    model.insertRows(row, 1);
    model.setData(model.index(row, 0), 1013);
    model.setData(model.index(row, 1), "Peter Gordon");
    model.setData(model.index(row, 2), 68500);
    model.submitAll();

以下是删除五行连续数据的方法:

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

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

完成对记录的修改后,应始终调用QSqlTableModel::submitAll(),以确保更改被写入数据库。

是否以及何时需要实际调用 submitAll(),取决于表的edit strategy 属性。默认策略为QSqlTableModel::OnRowChange ,这指定当用户选择另一行时,待处理的更改将应用到数据库中。 其他策略包括QSqlTableModel::OnManualSubmit (所有更改都会缓存到模型中,直到您调用 submitAll())和QSqlTableModel::OnFieldChange (不缓存任何更改)。这些策略主要在将QSqlTableModel 与视图配合使用时非常有用。

QSqlTableModel::OnFieldChange 似乎确实兑现了“永远无需显式调用 submitAll()”的承诺。不过,这里有两个陷阱:

  • 如果不进行任何缓存,性能可能会显著下降。
  • 如果修改了主键,在尝试填充该记录时,该记录可能会从指缝中溜走。

SQL 关系表模型

QSqlRelationalTableModel 在QSqlTableModel 的基础上扩展,以支持外键。外键是指一个表中的字段与另一个表的主键字段之间的一对一映射。例如,如果book 表中有一个名为authorid 的字段,该字段引用了author表中的id 字段,则我们说authorid 是一个外键。

显示城市和国家作为数值外键值的表显示已转换为文本字符串的城市和国家/地区的表格

左侧的截图显示了QTableView 中一个普通的QSqlTableModel 。外键(city 和country )并未解析为可读值。右侧的截图显示了一个QSqlRelationalTableModel ,其中外键已被解析为可读的文本字符串。

以下代码片段展示了如何配置QSqlRelationalTableModel :

    model->setTable("employee");

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

详情请参阅QSqlRelationalTableModel 的文档。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.