使用 SQL 模型类

除了QSqlQuery 之外,Qt 还提供了三个用于访问数据库的高级类。这些类是QSqlQueryModelQSqlTableModelQSqlRelationalTableModel

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

这些类派生自QAbstractTableModel (而 又继承自QAbstractItemModel ),可以方便地在QListViewQTableView 等项目视图类中显示数据库中的数据。在 "在表视图中显示数据"一节中有详细说明。

使用这些类的另一个好处是可以使代码更容易适应其他数据源。例如,如果您使用QSqlTableModel ,随后又决定使用 XML 文件而不是数据库来存储数据,那么这基本上只是将一种数据模型替换为另一种数据模型的问题。

SQL 查询模型

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

例如

    QSqlQueryModelmodel; model.setQuery("SELECT * FROM employee");for(inti= 0; i<model.rowCount();++i) {intid=model.record(i).value("id").toInt();        QStringname=model.record(i).value("name").toString();        qDebug() << id << name;
    }

使用QSqlQueryModel::setQuery() 设置查询后,可以使用QSqlQueryModel::record(int) 访问单条记录。您还可以使用QSqlQueryModel::data() 和从QAbstractItemModel 继承的任何其他函数。

此外,还有一个setQuery() 重载,它接收一个QSqlQuery 对象并对其结果集进行操作。这样,您就可以使用QSqlQuery 的任何功能来设置查询(例如,准备查询)。

SQL 表模型

QSqlTableModel 提供了一种读写模式,一次只对一个 SQL 表进行操作。

例如

    QSqlTableModelmodel; model.setTable("employee"); model.setFilter("salary > 50000"); model.setSort(2 Qt::DescendingOrder); model.select();for(inti= 0; i<model.rowCount();++i) { QStringname=model.record(i).value("name").toString();intsalary=model.record(i).value("salary").toInt();        qDebug() << name << salary;
    }

QSqlTableModel 是导航和修改单个 SQL 表的高级替代 。这种方法通常代码量较少,而且不需要 SQL 语法知识。QSqlQuery

使用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();

您还可以使用QSqlTableModel::data() 和QSqlTableModel::setData() 访问数据,它们继承于QAbstractItemModel 。例如,下面是如何使用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()似乎可以实现永远不需要显式调用 submitAll()的承诺。但这有两个隐患:

  • 在没有任何缓存的情况下,性能可能会大幅下降。
  • 如果你修改了主键,当你试图填充它时,记录可能会从你的指缝中溜走。

SQL 关系表模型

QSqlRelationalTableModel 扩展了 ,为外键提供了支持。外键是一个表中的字段与另一个表的主键字段之间的 1 对 1 映射。例如,如果 表中有一个名为 的字段,它指向作者表的 字段,我们就说 是一个外键。QSqlTableModel book authorid id authorid

左边的截图显示的是QTableView 表中的普通QSqlTableModel 。外键(citycountry )没有解析为人类可读的值。右边的截图显示的是QSqlRelationalTableModel ,外键已解析为人类可读的文本字符串。

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

    model->setTable("employee");

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

详情请查看QSqlRelationalTableModel 文档。

© 2025 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.