【Qt之QSqlTableModel】介绍及使用
描述
QSqlTableModel
类为单个数据库表提供可编辑的数据模型。
QSqlTableModel
是一个高级接口,用于从单个表中读写数据库记录。
它建立在较低级别的QSqlQuery
之上,可用于向QTableView
等视图类提供数据。
例如:
cpp
QSqlTableModel *model = new QSqlTableModel(parentObject, database);
// 设置表
model->setTable("employee");
// 设置编辑策略
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
// 更新
model->select();
// 设置表头
model->setHeaderData(0, Qt::Horizontal, tr("Name"));
model->setHeaderData(1, Qt::Horizontal, tr("Salary"));
QTableView *view = new QTableView;
view->setModel(model);
view->hideColumn(0); // don't show the name
view->show();
以上代码:
- 设置SQL表的名称和编辑策略
- 然后设置视图头中显示的标签
- 编辑策略指示用户在视图中所做的更改何时实际应用于数据库,取值为OnFieldChange、OnRowChange、OnManualSubmit。
QSqlTableModel
也可以用编程方式访问数据库,而不需要绑定到视图:
cpp
QSqlTableModel model;
model.setTable("employee");
model.select();
int salary = model.record(4).value("salary").toInt();
以上代码:
- 代码片段从
employee
查询SELECT *
的结果集中的记录4中提取工资字段 - 可以使用
setFilter()
设置过滤器,或者使用setSort()
修改排序顺序 - 最后,必须调用select()来用数据填充模型。
表模型示例说明了如何使用QSqlTableModel
作为QTableView
的数据源。
QSqlTableModel
不直接支持外键。
如果要解析外键,请使用QSqlRelationalTableModel
和QSqlRelationalDelegate
。
常用方法
- 枚举:
QSqlTableModel::EditStrategy
此枚举类型描述在编辑数据库中的值时选择的策略。
常量 | 值 | 描述 | 解释 |
---|---|---|---|
QSqlTableModel::OnFieldChange | 0 | All changes to the model will be applied immediately to the database. | 对模型的所有更改将立即应用于数据库。 |
QSqlTableModel::OnRowChange | 1 | Changes to a row will be applied when the user selects a different row. | 当用户选择另一行时,将应用对一行的更改。 |
QSqlTableModel::OnManualSubmit | 2 | All changes will be cached in the model until either submitAll() or revertAll() is called. | 在调用submitAll()或revertAll()之前,所有更改都将缓存在模型中。 |
注意:为了防止只将部分初始化的行插入数据库,OnFieldChange
的行为将像OnRowChange
一样用于新插入的行。
因此,一般设置为手动刷新:
cpp
pTableModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
-
QSqlDatabase database() const
获取模型连接的数据库对象。
-
EditStrategy editStrategy() const
返回当前的编辑策略。
-
int fieldIndex(const QString &fieldName) const
返回字段的索引,返回-1表示此模型内没有该字段。
cpp
qDebug().noquote() << "当前字段索引 :" << pTableModel->fieldIndex("name");
-
QString filter() const
获取当前设置的过滤。
-
bool insertRecord(int row, const QSqlRecord &record)
在位置行插入记录。如果
row
为负数,则将该记录追加到末尾。内部调用insertRows()
和setRecord()
。如果记录可以插入,则返回
true
,否则返回false
。更改立即提交
OnFieldChange
和OnRowChange
。失败不会在模型中留下新行。
cpp
QSqlRecord record = pTableModel->record();
qDebug().noquote() << "获取字段 :" << record.fieldName(0) << record.fieldName(1) << record.fieldName(2) << record.fieldName(3);
record.setValue("field0", "666");
record.setValue("field1", "666");
record.setValue("field2", 666);
record.setValue("field3", "666");
// 插入记录
// -1 表示在表的末尾插入新记录
qDebug().noquote() << "插入 :" << pTableModel->insertRecord(pTableModel->rowCount(), record);
-
bool isDirty(const QModelIndex &index) const
如果索引index处的值是被改的,则返回true,否则返回false。脏值是在模型中被修改但尚未写入数据库的值。
如果index无效或指向不存在的行,则返回false。
此函数还有重载:
bool isDirty() const
意思就是:
这是一个重载函数。
如果模型包含未提交给数据库的修改值,则返回true,否则返回false。
-
QSqlIndex primaryKey() const
返回当前表的主键,如果表未设置或没有主键,则返回空
QSqlIndex
。 -
QSqlRecord record(int row) const
返回模型中第一行的记录。
如果
row
是有效行的索引,则将使用该行的值填充记录。如果模型没有初始化,将返回一个空记录。
此函数还有重载:
QSqlRecord record() const
意思就是:
这是一个重载函数。
返回一个空记录,只有字段名称;此函数可用于检索记录的字段名。
-
void revertRow(int row)
恢复指定行的所有改变。
-
void setFilter(const QString &filter)
将当前过滤器设置为
filter
。过滤器是一个不带关键字
WHERE
的SQL
WHERE
子句(例如,name='Josephine'
)。如果已经用数据库中的数据填充了模型,则模型将使用新的过滤器重新选择它。否则,过滤器将在下次调用
select()
时应用。
cpp
QSqlTableModel* pTableModel = new QSqlTableModel(ui->tableView, db);
pTableModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
pTableModel->setTable("\"tableTest\"");
// 未选择
pTableModel->setFilter("name = '666'");
// 执行setFilter操作
pTableModel->select();
if (pTableModel->lastError().isValid()) {
qDebug() << "Error:" << pTableModel->lastError();
}
ui->tableView->setModel(pTableModel);
// 当前字段索引
qDebug().noquote() << "当前字段索引 :" << pTableModel->fieldIndex("name");
// 重新选择
pTableModel->setFilter("name = '22'");
-
bool setRecord(int row, const QSqlRecord &values)
将值应用于模型中的行。源字段和目标字段按字段名映射,而不是按记录中的位置映射。
请注意,将保留值中生成的标志,并确定在将更改提交给数据库时是否使用相应的字段。调用者应该记得将数据库提供值的字段(比如自动增加的ID)的生成标志设置为FALSE。
对于编辑策略
OnFieldChange
和OnRowChange
,只有当其他行没有缓存更改时,一行才可能接收到更改。更改会立即提交。提交的更改在失败时不会恢复。如果所有值都可以设置,则返回
true
;否则返回false
。 -
void setSort(int column, Qt::SortOrder order)
将列的排序顺序设置为
order
。这不会影响当前数据,要使用新的排序顺序刷新数据,请调用select()。 -
void setTable(const QString &tableName)
将模型操作的数据库表设置为
tableName
。不从表中选择数据,但获取其字段信息。要用表的数据填充模型,请调用
select()
。可以使用
lastError()
检索错误信息。
cpp
pTableModel->setTable("\"tableTest\"");
QString tableName() const
获取当前选择的表名
槽函数
-
bool submit()
从
QAbstractItemModel::submit()
重新实现。当用户停止编辑当前行时,项委托调用这个重新实现的槽。
如果模型的策略设置为
OnRowChange
或OnFieldChange
,则提交当前编辑的行。对OnManualSubmit
策略不做任何操作。使用
submitAll()
为OnManualSubmit
策略提交所有挂起的更改。成功时返回
true
;否则返回false
。使用lastError()
查询详细的错误信息。不会自动重新填充模型。提交的行在成功时从数据库中刷新。
-
bool submitAll()
提交所有挂起的更改,并在成功时返回true。错误时返回false,详细的错误信息可以通过
lastError()
获得。在
OnManualSubmit
中,一旦成功,模型将被重新填充。任何呈现它的视图都将失去其选择。注意:在
OnManualSubmit
模式下,当submitAll()
失败时,已经提交的更改不会从缓存中清除。这允许事务回滚并重新提交,而不会丢失数据。 -
void revert()
从
QAbstractItemModel::revert()
重新实现。当用户取消编辑当前行时,项目委托调用这个重新实现的槽。
如果模型的策略设置为
OnRowChange
或OnFieldChange
,则恢复更改。对OnManualSubmit策略不做任何操作。 使用
revertAll()来恢复
OnManualSubmit策略的所有挂起的更改,或者使用
revertRow()`来恢复特定的行。 -
void revertAll()
重置所有缓存操作。
-
bool select()
使用通过
setTable()
设置的表中的数据填充模型,使用指定的筛选和排序条件,如果成功则返回true;否则返回false。注意:调用
select()
将恢复所有未提交的更改并删除所有插入的列。 -
bool selectRow(int row)
使用与主键值匹配的数据库表行中的值刷新模型中的行。如果没有主键,所有列值必须匹配。如果没有找到匹配的行,模型将显示空行。
如果成功返回true;否则返回false。
信号
void beforeDelete(int row)
该信号由deleteRowFromTable()
在从当前活动的数据库表中删除行之前发出。void beforeInsert(QSqlRecord &record)
该信号由insertRowIntoTable()
在将新行插入当前活动的数据库表之前发出。要插入的值存储在记录中,可以在插入之前进行修改。void beforeUpdate(int row, QSqlRecord &record)
在使用record
中的值更新当前活动数据库表中的行之前,updateRowInTable()
会发出这个信号。
注意,只有标记为生成的值才会被更新。生成标志可以用QSqlRecord::setGenerated()
设置,用QSqlRecord::isGenerated()
检查。void primeInsert(int row, QSqlRecord &record)
当在当前活动的数据库表的给定行中发起插入时,该信号由insertRows()发出。record参数可以写入(因为它是一个引用),例如用默认值填充一些字段,并设置字段的生成标志。在处理此信号时,不要尝试通过setData()或setRecord()等其他方法编辑记录。
示例
在.pro中添加QT += sql
包含头文件
cpp
#include <QDebug>
#include <QSqlTableModel>
#include <QSqlDatabase>
#include <QSqlRecord>
#include <QSqlError>
初始化
cpp
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("xxx/xxx/xxx.db");
bool ok = db.open();
QSqlTableModel* pTableModel = new QSqlTableModel(ui->tableView, db);
pTableModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
pTableModel->setTable("\"tableTest\"");
pTableModel->setFilter("name = '666'");
pTableModel->select();
if (pTableModel->lastError().isValid()) {
qDebug() << "Error:" << pTableModel->lastError();
}
ui->tableView->setModel(pTableModel);
// 当前字段索引
qDebug().noquote() << "当前字段索引 :" << pTableModel->fieldIndex("name");
pTableModel->setFilter("name = '666'");
插入
cpp
QSqlTableModel* pTableModel = (QSqlTableModel*)ui->tableView->model();
// 实现以下代码,插入空行后进行数据插入,会插入失败。
//pTableModel->insertRow(pTableModel->rowCount());
QSqlRecord record = pTableModel->record();
qDebug().noquote() << "获取字段 :" << record.fieldName(0) << record.fieldName(1) << record.fieldName(2) << record.fieldName(3);
record.setValue("field0", "66");
record.setValue("field1", "66");
record.setValue("field2", 66);
record.setValue("field3", "66");
// 插入记录
qDebug().noquote() << "插入 :" << pTableModel->insertRecord(pTableModel->rowCount(), record); // -1 表示在表的末尾插入新记录
提交
cpp
QSqlTableModel* pTableModel = (QSqlTableModel*)ui->tableView->model();
pTableModel->submitAll();