首页 > 解决方案 > 通过 QIdentityProxyModel 向 QSqlTableModel 添加数据失败

问题描述

我有一个基于QSqlTableModel

class QuestionSqlTableModel : public QSqlTableModel
{
    Q_OBJECT
public:
    explicit QuestionSqlTableModel(QObject *parent = nullptr,
                                   const QSqlDatabase &db = QSqlDatabase());

};
QuestionSqlTableModel::QuestionSqlTableModel(
    QObject *parent, const QSqlDatabase &db)
    : QSqlTableModel{parent, db}
{
    setEditStrategy(EditStrategy::OnFieldChange);
}

现在要将列映射到要在 qml 中使用的角色,我将此模型安装到派生自QIdentityProxyModel.

一切似乎都很好。我可以从现有数据库中读取数据并通过QIdentityProxyModel.

现在从 QML 我想添加一个新的数据行。为此,我在QIdentityProxyModel.

该模型的完整代码:

#include <QObject>
#include <QIdentityProxyModel>

class QuestionsProxyModel : public QIdentityProxyModel
{
    Q_OBJECT

    enum questionRoles {
        idRole = Qt::UserRole + 1,
        askedQuestionRole,
        answer1Role,
        answer2Role,
        answer3Role,
        answer4Role,
        correctAnswerRole,
        pictureRole
    };

public:
    QuestionsProxyModel(QObject* parent = nullptr);

    QHash<int, QByteArray> roleNames() const override;

    Q_INVOKABLE QVariant data(const QModelIndex &index, int role) const override;

    Q_INVOKABLE bool addNewEntry(const QString& askedQuestion,
        const QString& answer1,
        const QString& answer2,
        const QString& answer3,
        const QString& answer4,
        int correctAnswer,
        const QString& picturePath);
private:
    QModelIndex mapIndex(const QModelIndex &index, int role) const;
};

#include <QDebug>
#include <QPixmap>
#include <QBuffer>

#include <QByteArray>

namespace QuestionColumn
{
    static constexpr auto id = 0;
    static constexpr auto askedQuestion = 1;
    static constexpr auto answer1 = 2;
    static constexpr auto answer2 = 3;
    static constexpr auto answer3 = 4;
    static constexpr auto answer4 = 5;
    static constexpr auto correct_answer = 6;
    static constexpr auto picture = 7;
}


QuestionsProxyModel::QuestionsProxyModel(QObject* parent)
    :QIdentityProxyModel(parent)
{
}

QHash<int, QByteArray> QuestionsProxyModel::roleNames() const
{
    QHash <int,QByteArray> roles;
    roles[idRole] = "id";
    roles[askedQuestionRole] = "askedQuestion";
    roles[answer1Role] = "answer1";
    roles[answer2Role] = "answer2";
    roles[answer3Role] = "answer3";
    roles[answer4Role] = "answer4";
    roles[correctAnswerRole] = "correctAnswer";
    roles[pictureRole] = "picture";

    return roles;
}

QVariant QuestionsProxyModel::data(const QModelIndex &index, int role) const
{
    QModelIndex newIndex = mapIndex(index, role);
    if (role == idRole
            || role == askedQuestionRole
            || role == answer1Role
            || role == answer2Role
            || role == answer3Role
            || role == answer4Role
            || role == correctAnswerRole
            || role == pictureRole) {

        return QIdentityProxyModel::data(newIndex, Qt::DisplayRole);
    }
    return QIdentityProxyModel::data(newIndex, role);
}

bool QuestionsProxyModel::addNewEntry(const QString &askedQuestion,
                                    const QString &answer1,
                                    const QString &answer2,
                                    const QString &answer3,
                                    const QString &answer4,
                                    int correctAnswer,
                                    const QString &picturePath)
{
    Q_ASSERT(!askedQuestion.isEmpty());
    Q_ASSERT(!answer1.isEmpty());
    Q_ASSERT(!answer2.isEmpty());
    Q_ASSERT(!answer3.isEmpty());
    Q_ASSERT(!answer4.isEmpty());
    Q_ASSERT(correctAnswer >= 1 && correctAnswer <= 4);


    auto newRow = rowCount();

    if(!insertRow(newRow, QModelIndex{})) {
        return false;
    }
    if(!setData(index(newRow, QuestionColumn::id), newRow + 1)) {
        removeRow(newRow);
        return false;
    }
    if(!setData(index(newRow, QuestionColumn::askedQuestion),
                           askedQuestion)) {
        removeRow(newRow);
        return false;
    }
    if(!setData(index(newRow, QuestionColumn::answer1), answer1)) {
        removeRow(newRow);
        return false;
    }
    if(!setData(index(newRow, QuestionColumn::answer2), answer2)) {
        removeRow(newRow);
        return false;
    }
    if(!setData(index(newRow, QuestionColumn::answer3), answer3)) {
        removeRow(newRow);
        return false;
    }
    if(!setData(index(newRow, QuestionColumn::answer4), answer4)) {
        removeRow(newRow);
        return false;
    }
    if(!setData(index(newRow, QuestionColumn::correct_answer), correctAnswer)) {
        removeRow(newRow);
        return false;
    }
    if(!setData(index(newRow, QuestionColumn::picture), picturePath)) {
        removeRow(newRow);
        return false;
    }
    return true;
}

QModelIndex QuestionsProxyModel::mapIndex(const QModelIndex &source, int role) const
{
    switch(role) {
    case idRole:
        return createIndex(source.row(), QuestionColumn::id);
    case askedQuestionRole:
        return createIndex(source.row(), QuestionColumn::askedQuestion);
    case answer1Role:
        return createIndex(source.row(), QuestionColumn::answer1);
    case answer2Role:
        return createIndex(source.row(), QuestionColumn::answer2);
    case answer3Role:
        return createIndex(source.row(), QuestionColumn::answer3);
    case answer4Role:
        return createIndex(source.row(), QuestionColumn::answer4);
    case correctAnswerRole:
        return createIndex(source.row(), QuestionColumn::correct_answer);
    case pictureRole:
        return createIndex(source.row(), QuestionColumn::picture);
    }
    return source;
}

现在,如果我使用该方法QuestionsProxyModel::addNewEntry,我希望所有这些数据都会添加到 SQL 数据库中,但事实并非如此。

奇怪的是在 QML 的视图中我可以看到添加的数据,但是在关闭应用程序时它没有存储在数据库中。insertRow除了使用和setData保存到数据库之外,我还需要做些什么吗?

addNewEntry只适用于第一次。第二次insertRow简单地返回 false。

标签: c++qt

解决方案


我发现数据只保存到调用QSqlTableModel时的数据库中submit

所以我在末尾添加addNewEntryQuestionsProxyModel

auto sqlModel = qobject_cast<QSqlTableModel*>(sourceModel());
if(sqlModel) {
    sqlModel->submit();
}

我觉得这个解决方案有点 hacky。至少如果基础模型不是 a仍然可以正常工作QSqlTableModelQuestionsProxyModel


推荐阅读