Planned maintenance: From Sunday 8th December 10:00 CET there will be changes to try and solve the caching issues that have been experienced. If anyone has a problem connecting after this period then please PM @AndyS or any of the moderators.

Unable to read data from QSqlTableModel in Qml : "role names" are not defined



  • So I subclassed QSqlTableModel in my application. Then I set this model as a context property to be accessible in QML assigning it to a ListView. Then I set a simple Label as a delegate with text set to my role name (e.g. Name), but I always get the following error:

    ReferenceError: Name is not defined
    

    Below is my code

    #include "sqlmodel.h"
    #include <QSqlDatabase>
    #include <QSqlError>
    #include <QSqlRecord>
    #include <QStandardPaths>
    #include <QSqlQuery>
    
    SqlModel::SqlModel(QObject *parent )
        : QSqlTableModel( parent )
    {
        openDataBase();
    }
    QVariant SqlModel::data(const QModelIndex &index, int role) const{
    
        QVariant value;
        if(role < Qt::UserRole)
        {
            value = QSqlTableModel::data(index, role);
        }
        else {
            int columnIdx = role - Qt::UserRole - 1;
            QModelIndex modelIndex = this->index(index.row(), columnIdx);
            value = QSqlTableModel::data(modelIndex, Qt::DisplayRole);
        }
        return value;
    }
    
    QHash<int, QByteArray> SqlModel::roleNames() const
    {
    //    QHash<int, QByteArray> roles;
    //    roles[Qt::UserRole + 1] = "Identifier";
    //    roles[Qt::UserRole + 2] = "Name";
    //    roles[Qt::UserRole + 3] = "ElementColor";
    //    roles[Qt::UserRole + 4] = "FileUrl";
    //    roles[Qt::UserRole + 5] = "HomeRss";
    //    roles[Qt::UserRole + 6] = "ListPos";
    
    
    //    return roles;
        QHash<int, QByteArray> roles;
        for (int i = 0; i < this->columnCount(); i++) {
            QString role= this->headerData(i, Qt::Horizontal).toString();
            qDebug() << role;
            roles[Qt::UserRole + i + 1] = QVariant(role).toByteArray();
            qDebug()<<this->headerData(i, Qt::Horizontal);
        }
        return roles;
    }
    
    bool SqlModel::insertItem(const QVariantMap itemMap)
    {
        QSqlRecord sqlRecord = this->record();
        sqlRecord.setValue("Identifier", itemMap.value("Identifier").toInt());
        sqlRecord.setValue("Name", itemMap.value("Name").toString());
        sqlRecord.setValue("ElementColor", itemMap.value("ElementColor").toString());
        sqlRecord.setValue("FileUrl", itemMap.value("FileUrl").toString());
        sqlRecord.setValue("HomeRss", itemMap.value("HomeRss").toString());
        sqlRecord.setValue("ListPos",  itemMap.value("ListPos").toInt());
    
        bool success = this->insertRecord(rowCount(), sqlRecord);
    
        if(!success)
            qWarning() << "UNABLE TO ADD ITEM TO DATABASE" << this->lastError().text();
        else{
            this->submit();
        }
    }
    
    
    void SqlModel::openDataBase()
    {
        QSqlDatabase db;
    
        const QString DRIVER("QSQLITE");
    
        if(QSqlDatabase::isDriverAvailable(DRIVER)) {
            db = QSqlDatabase::addDatabase(DRIVER);
            QString storagePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
            db.setDatabaseName(storagePath+"/database.sqlite");
    
            if(!db.open())
                qWarning() << "ERROR: " << db.lastError();
            else{
                qDebug( "Opening database %s", qPrintable( db.databaseName() ) );
                QSqlQuery query("CREATE TABLE IF NOT EXISTS home (Identifier INTEGER PRIMARY KEY,"
                                "Name TEXT, "
                                "ElementColor TEXT, "
                                "FileUrl TEXT, "
                                "HomeRss TEXT, "
                                "ListPos INTEGER)");
    
                if(!query.exec())
                    qWarning() << "DATABASE ERROR: " << query.lastError().text();
    
                this->setTable("home");
                this->setEditStrategy(QSqlTableModel::OnManualSubmit);
                this->select();
            }
        }
        else{
            qWarning() << "SQL DRIVER " << DRIVER << "NOT AVAILBLE" << db.lastError();
        }
    }
    
    


  • @SGaist Ok that makes sense. Thank you


  • Lifetime Qt Champion

    Hi,

    Did you already saw that wiki entry about that subject ?



  • @SGaist said in Unable to read data from QSqlTableModel in Qml : "role names" are not defined:

    Hi,

    Did you already saw that wiki entry about that subject ?

    Yeah, my code is partially based on that


  • Lifetime Qt Champion

    Then can you also share the QtQuick part so your code can be properly tested ?



  • @SGaist yeah sure this is my qml:

    import QtQuick 2.9
    import QtQuick.Controls 2.2
    import QtQuick.Layouts 1.4
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Scroll")
    
        ColumnLayout{
            anchors.fill: parent
            ScrollView {
                Layout.fillWidth: true
                Layout.fillHeight: true
                ListView {
                    width: parent.width
                    model: sqlModel
    
                    delegate: ItemDelegate {
                        text: "Item" + (Name) // if you remove (Name) and just put a string, then add it shows the string
                        width: parent.width
                    }
                }
            }
    
            Button{
                z: 15
                text: "Add"
                onClicked:{
                    var milliseconds = new Date().getTime();
                    var myObject = {Identifier: milliseconds, Name: "MyItem", ElementColor: "blue", FileUrl: "http://", HomeRss: "http:??", ListPos: 0}
                    sqlModel.insertItem(myObject)
                }
            }
        }
    }

  • Lifetime Qt Champion

    I didn't realise, there missing parts like your model header and the main.cpp file.

    Is your project accessible somewhere ?



  • @SGaist said in Unable to read data from QSqlTableModel in Qml : "role names" are not defined:

    I didn't realise, there missing parts like your model header and the main.cpp file.

    Is your project accessible somewhere ?

    Unfortunately not but the header and main file implementation is quite simple. Here is the header:

    #include <QObject>
    #include <QDebug>
    #include <QSqlTableModel>
    #include <QQmlAutoPropertyHelpers.h>
    
    class SqlModel : public QSqlTableModel
    {
        Q_OBJECT
    public:
        SqlModel(QObject* parent = nullptr);
        Q_INVOKABLE QVariant data(const QModelIndex &index, int role) const override;
        QHash<int, QByteArray> roleNames() const override;
    
        Q_INVOKABLE bool insertItem(const QVariantMap itemMap);
    private:
        void openDataBase();
    };
    

    In my main.cpp I do the following:

    #include "sqlmodel.h"
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
        app.setOrganizationDomain("daljit97");
    
        qmlRegisterType<SqlModel>();
    
        SqlModel *sqlHomeModel = new SqlModel();
        QQmlApplicationEngine engine;
    
        QQuickStyle::setStyle("Material");
        QQmlContext *qmlContext = engine.rootContext();
        qmlContext->setContextProperty("sqlHomeModel", sqlHomeModel);
    
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        if (engine.rootObjects().isEmpty())
            return -1;
    
        return app.exec();
    }
    

  • Lifetime Qt Champion

    Sorry but with the current bits and pieces I don't have anything on screen. Can you maybe refactor that to ensure it goes up to the screen ?



  • @SGaist Here I uploaded a fully working project where the problem persists https://www.dropbox.com/s/qsyqds61zxdxkyx/SqlModelTest.zip?dl=0.
    When you click the add button, it shows: Name not defined.
    EDIT: I also update the qml file example provided here


  • Lifetime Qt Champion

    That's because you are creating your database connection after you created your model. So the model is using the default database connection that hasn't been created yet.

    Move the database initialisation part outside of your model and somewhere before your create that object.



  • @SGaist Ok that makes sense. Thank you