Adding data throught QIdentityProxyModel to QSqlTableModel fails

  c++, qt

I’m really confused about this issue.

I have a model based on 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);
}

Now to map columns to roles to use in qml I install this model into a model derrived from QIdentityProxyModel.

Everything seems to work fine. I can read the data from an existing database and display it in qml through the QIdentityProxyModel.

Now from QML I want to add a new row with data. For that I added a method in the child of QIdentityProxyModel.

The whole code for this model:

#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;
}

Now if I use the method QuestionsProxyModel::addNewEntry I would expect that all this data does get added to the SQL database but it doesn’t.

The strange thing is in the View in QML I can see the added data but on closing the application It is not stored in the database. Do I have to do something in addion of of using insertRow and setData to save to the database?

Also addNewEntry only works the first time. The second time insertRow simply returns false.

Source: Windows Questions C++

LEAVE A COMMENT