Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QML, QSqlTableModel: not saving data



  • Hi, my data is being displayed by rolenames successfully but "setData" is not working. This function is receiving everything right from qml but the final call to

     QSqlTableModel::setData
    

    does not work, returns "false" & there are no errors.

    QVariant ItemModel::data(const QModelIndex & index, int role) const {
        // qDebug() << role_names.value(role);
        //  QString role_str = QString(roles.value(role));
        qDebug() << index.row();
        QModelIndex modelIndex = this->index(index.row(), role - Qt::UserRole - 1 );
        return  QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
    }
    
    bool ItemModel::setData(const QModelIndex &index, const QVariant &value, int role) {
        qDebug() << role_names.value(role) << " " << value << " " << index.row() << " " << index.column() << " " << role - Qt::UserRole - 1;
        QModelIndex modelIndex = this->index(index.row(), role - Qt::UserRole - 1);
      //  this->query().seek(index.row());
      //  qDebug() << this->query().record().value(1);
    
        qDebug() << QSqlTableModel::setData(modelIndex,value);
        qDebug() << lastError();
        emit dataChanged(modelIndex,modelIndex);
        return true;
    }
    
    void ItemModel::generateRoleNames()  {
        this->role_names.clear();
        for (int i = 0; i < record().count(); ++i)   {
            role_names[Qt::UserRole + i + 1] = record().fieldName(i).toUtf8();
        }
    }
    

    I have experience with abstract models but SQL models are giving me hardtime. I have no idea why it is not working. Any help will be much appreciated.


  • Lifetime Qt Champion

    Hi,

    @Bilal_Khan said in QML, QSqlTableModel: not saving data:

    modelIndex

    Are you sure this index is valid ?



  • This modelIndex is computed in both functions (data() & setData()) in the same way but it does not work while setting data. I have also tried this->index with different literal values but no success so far..

    itemModel->setEditStrategy(QSqlTableModel::OnFieldChange);
    


  • Update (UBUNTU 20.04/ Qt-5.13 & 6.12/ SQLITE3 & PSQL):

    • I no longer override setData and directly call the parent's implementation:
    qDebug() <<  itemModel->setData(itemModel->index(0, 1), "NEW VALUE", Qt::EditRole); // false
     qDebug() << itemModel->lastError();   // QSqlError("", "", "")
    

    but no vain.

    • Surprisingly, there are no errors on passing invalid index.

    • I confirm that setRecord is also not working (no errors)

     ItemModel *itemModel = new ItemModel(nullptr,db);
     itemModel->setEditStrategy(QSqlTableModel::OnFieldChange);
     itemModel->setTable("items");
     itemModel->generateRoleNames();
     itemModel->select();
     qDebug() <<  itemModel->rowCount(); // 2
     itemModel->query().seek(0);
     QSqlRecord rec = itemModel->query().record();
    
     rec.setValue(1, QString("SOMETHING"));
     qDebug() << itemModel->setRecord(0,rec);  //true
    
     QModelIndex index = itemModel->index(0, 0);
     qDebug() << "Update" << itemModel->data(index, 258);   // old value returned
    


  • It's just the problem with subclassing. setData does not work.

      enum ItemRoles {
            CONTENTROLE = Qt::UserRole + 1,
            TYPEROLE = Qt::UserRole + 2,
            VIEWSROLE = Qt::UserRole + 3,
            WEIGHTROLE
        };
    QHash<int, QByteArray> ItemModel::roleNames() const  {
           QHash<int, QByteArray> roles;
           roles[CONTENTROLE] = "content";
           roles[TYPEROLE] = "type";
           roles[VIEWSROLE] = "views";
           roles[WEIGHTROLE] = "weight";
           return roles;
    }
    bool ItemModel::setData(const QModelIndex &index, const QVariant &value, int role) {
        QModelIndex modelIndex = this->index(index.row(), role - Qt::UserRole);
    
        qDebug() << QSqlTableModel::setData(modelIndex,value, Qt::EditRole); // true
        qDebug() << lastError();
        emit dataChanged(modelIndex,modelIndex);
        return true;
    }
    
    //
    QModelIndex index = itemModel->index(0, 0);
    itemModel->setData(index, "VALUE",  itemModel->CONTENTROLE);
     qDebug() <<  itemModel->data(index, itemModel->CONTENTROLE); // unchanged data
    

  • Lifetime Qt Champion

    What if you call submit after setRecord ?



  • Yes, I did but does not work


  • Lifetime Qt Champion

    Can you provide a minimal compilable example so that it's possible to reproduce your issue.



  • Hi,
    Thank you @SGaist for your kind support ... so far

    As you could see , I have made some changes. Now, after the update in setData, the data function returns qvariant(invalid).

    Project Link:
    Test Qt Project



  • @SGaist , sorry to bother you again. Did you check it, what you have found?


  • Lifetime Qt Champion

    This works correctly.

    #ifndef ITEMMODEL_H
    #define ITEMMODEL_H
    
    #include <QSqlTableModel>
    
    class ItemModel : public QSqlTableModel {
        Q_OBJECT
    public:
    
        enum ItemRoles {
            IDROLE = Qt::UserRole + 1,
            CONTENTROLE = Qt::UserRole + 2,
            TYPEROLE = Qt::UserRole + 3,
            VIEWSROLE = Qt::UserRole + 4,
            WEIGHTROLE
        };
        Q_ENUMS(ItemRoles)
    
        ItemModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase());
    
        QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
        bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
    
        QHash<int, QByteArray> roleNames() const;
    
    private:
        Q_DISABLE_COPY(ItemModel);
    
        QModelIndex indexForRole(const QModelIndex& index, int role) const;
    };
    
    #endif // ITEMMODEL_H
    
    #include "ItemModel.h"
    
    ItemModel::ItemModel(QObject *parent, QSqlDatabase db):
        QSqlTableModel(parent, db)
    {
    
    }
    
    QVariant ItemModel::data(const QModelIndex & index, int role) const
    {
        return QSqlTableModel::data(indexForRole(index, role), Qt::EditRole);
    }
    
    
    bool ItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
    {
        return QSqlTableModel::setData(indexForRole(index, role), value, Qt::EditRole);
    }
    
    
    QHash<int, QByteArray> ItemModel::roleNames() const  {
           QHash<int, QByteArray> roles;
           roles[IDROLE] = "id";
           roles[CONTENTROLE] = "content";
           roles[TYPEROLE] = "type";
           roles[VIEWSROLE] = "views";
           roles[WEIGHTROLE] = "weight";
           return roles;
    }
    
    
    QModelIndex ItemModel::indexForRole(const QModelIndex& index, int role) const
    {
        int row = index.row();
        int column = index.column();
        if (role > Qt::UserRole) {
            column = role - Qt::UserRole - 1;
        }
        return this->index(row, column);
    }
    

Log in to reply