使用 SQL 模型类

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

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

这些类都从 QAbstractTableModel 继承(后者又继承自 QAbstractItemModel),使得在 QListViewQTableView 等项视图类中显示数据库数据变得容易。这将在 在表格视图中显示数据 部分详细解释。

使用这些类的另一个优点是可以使你的代码更容易适应其他数据源。例如,如果你使用 QSqlTableModel,后来决定用 XML 文件而不是数据库来存储数据,本质上只需用一个数据模型替换另一个。

SQL 查询模型

QSqlQueryModel 提供基于 SQL 查询的可读模型。

示例

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

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

SQL 表模型

QSqlTableModel 提供了对单个 SQL 表进行操作的读写模型。

示例

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

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

QSqlTableModelQSqlQuery 的一个高级替代品,用于导航和修改单个 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()取决于表的编辑策略。默认策略是QSqlTableModel::OnRowChange,它指定在用户选择不同的行时应用挂起的更改。其他策略包括QSqlTableModel::OnManualSubmit(将所有更改缓存到模型中,直到您调用submitAll())和QSqlTableModel::OnFieldChange(不缓存任何更改)。这些策略在QSqlTableModel与视图一起使用时非常有用。

QSqlTableModel::OnFieldChange似乎承诺您永远不需要显式地调用submitAll()。但是有两个陷阱:

  • 在没有缓存的情况下,性能可能会显著下降。
  • 如果您修改主键,记录可能在您尝试填充时通过您的手指滑走。

SQL关系表模型

QSqlRelationalTableModel扩展QSqlTableModel以提供对外键的支持。外键是一个表中的一个字段与其他表的主键字段之间的1对1映射。例如,如果有一个名为book的表有一个名为authorid的字段,它引用作者表的id字段,那么我们说authorid是一个外键。

左边的截图显示了一个普通QSqlTableModelQTableView中的样子。外键(citycountry)没有被解析为可读的文本值。右边的截图显示了一个QSqlRelationalTableModel,其外键被解析为人类可读的文本字符串。

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

    model->setTable("employee");

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

有关详细信息,请参阅QSqlRelationalTableModel文档。

© 2024 Qt公司有限公司的版权。本文件中包含的文档贡献是相关所有者的版权。本文件中所提供的文档是根据自由软件基金会发布的GNU自由文档许可证版本1.3的条款许可的。Qt及其相应的标志是芬兰和/或其他国家的Qt公司有限公司的商标。所有其他商标均为各自所有者的财产。