如何让QSqlTableModel(OnManualSubmit)显示缓存脏数据?
这个问题的核心在于QSqlTableModel默认的data()方法只会返回数据库中已提交的数据,而你通过OnManualSubmit策略暂存的未提交修改(脏数据)是存在模型内部缓存里的,不会自动被视图获取到。要让视图实时显示这些待提交的更改,你需要在子类化的DbTableModel中重写data()方法,优先返回缓存中的脏数据。
1. 重写data()方法,优先返回脏数据
在你的DbTableModel类中,重写data()函数,逻辑是:先检查当前行/列是否有未提交的修改,如果有,就返回缓存里的新值;没有的话再回退到父类的默认实现。
首先在头文件中声明重写:
class DbTableModel : public QSqlTableModel { Q_OBJECT Q_ENUM(CustomRoles) // 暴露枚举给QML使用 public: explicit DbTableModel(QObject *parent = nullptr, const QSqlDatabase &db = QSqlDatabase()); enum CustomRoles { NameRole = Qt::UserRole + 1, SpecialTextRole, DescriptionRole }; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QHash<int, QByteArray> roleNames() const override; private: // 辅助方法:将自定义角色映射到数据库列索引 int roleToColumn(int role) const; };
然后实现data()和辅助方法:
QVariant DbTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } // 处理自定义角色 int column = roleToColumn(role); if (column != -1) { // 检查当前行是否有未提交的修改 if (isDirty(index.row())) { QSqlRecord dirtyRecord = record(index.row()); // 如果该列被修改过,返回缓存的新值 if (dirtyRecord.isModified(column)) { return dirtyRecord.value(column); } } // 没有脏数据时,返回数据库中的原始值 QModelIndex columnIndex = this->index(index.row(), column); return QSqlTableModel::data(columnIndex, Qt::DisplayRole); } // 处理Qt默认角色(如DisplayRole等) return QSqlTableModel::data(index, role); } int DbTableModel::roleToColumn(int role) const { switch (role) { case NameRole: return fieldIndex("name"); // 替换为你的数据库列名 case SpecialTextRole: return fieldIndex("specialText"); case DescriptionRole: return fieldIndex("description"); default: return -1; } } // 别忘了实现roleNames()来注册自定义角色 QHash<int, QByteArray> DbTableModel::roleNames() const { QHash<int, QByteArray> roles = QSqlTableModel::roleNames(); roles[NameRole] = "name"; roles[SpecialTextRole] = "specialText"; roles[DescriptionRole] = "description"; return roles; }
2. 修正QML中的setData调用
你当前QML里用1作为角色参数是硬编码,容易出错。因为我们已经用Q_ENUM暴露了自定义角色,直接用枚举值更可靠:
onEditingFinished: { console.log(styleData.row + ", name: " + text); SpecialSqlModel.setData(styleData.row, text, SpecialSqlModel.NameRole); }
3. 验证效果
现在当你在QML中编辑字段后,模型会将修改存入缓存,data()方法会优先返回这个缓存值,视图就能实时显示未提交的更改。当你调用submitAll()提交后,脏数据会写入数据库,缓存被清空;调用revertAll()则会丢弃缓存,视图回到原始数据。
原理说明
QSqlTableModel在OnManualSubmit模式下,所有修改都会先存入内部的QSqlRecord缓存,isDirty()方法可以检查某行是否有未提交修改,record(row)可以获取包含修改的记录,isModified(column)则能判断具体列是否被修改。重写data()后,我们就把这些缓存数据暴露给了视图。
内容的提问来源于stack exchange,提问作者martin




