You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何让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

火山引擎 最新活动