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

Yet another QSqlTableModel removeRows issue



  • Here I read:

    Removes count rows starting at row. Since this model does not support hierarchical structures, parent must be an invalid model index.
    When the edit strategy is OnManualSubmit, deletion of rows from the database is delayed until submitAll() is called.
    Before a row is deleted from the database, the beforeDelete() signal is emitted.

    In my application I do:

    void DialogTechnologies::on_btnRemove_clicked()
    {
        if (ui->table->selectionModel()->hasSelection())
        {
            int row = ui->table->selectionModel()->currentIndex().row();
            _model->removeRow(row);
            _model->submitAll();
        }
    }
    
    void DialogTechnologies::on_btnRemoveAll_clicked()
    {
        _model->removeRows(0, _model->rowCount());
        _model->submitAll();
    }
    

    Both remove* methods return true but nothing happens on the database.
    Questions:

    1. what does actually mean that "parent must be an invalid model index"?
    2. what signal should I use to refresh the view, after the row(s) deletion? Is dataChanged emitted?

    As side note: in the help integrated in the IDE I read instead:

    The base class implementation does nothing and returns false.

    This makes no sense to me. First, it returs true and then why they would have implemented the insertRows function but not the removeRows one? By the way, also for insertRows the help says the "base class implementation does nothing and returns false", but this is not true - it works and it returns true! I'm confused...



  • @Mark81

    Both remove* methods return true

    Have to take your word on that, because it's not in your code....

    but nothing happens on the database.

    How do you check that?

    The base class implementation does nothing and returns false.

    That's for whatever the base class is, maybe QAbstractItemModel, I haven't looked. QSqlTableModel does have an implementation.

    what does actually mean that "parent must be an invalid model index"?

    bool QSqlTableModel::removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) has a default QModelIndex() which is "an invalid model index", you are calling it right, don't worry about it.

    what signal should I use to refresh the view, after the row(s) deletion? Is dataChanged emitted?

    dataChanged is only for updates. For insertion/deletion it's beginRemoveRows/rowsAboutToBeRemoved/rowsRemoved() etc. But QSqlTableModel does this for you. You don't have to raise signals, just ensure your view is properly connected to model.

    Why does it (apparently) not work? I don't know, but I do know you need to check the returns result of the _model->submitAll(); because maybe it's failing at database side.... When you write code like this, please look at return results and always check all of them, especially while developing/you don't know what is going on....



  • @JonB said in Yet another QSqlTableModel removeRows issue:

    @Mark81
    Have to take your word on that, because it's not in your code....

    I printed the return values with qDebug().

    How do you check that?

    With "DB Browser for SQLite".

    That's for whatever the base class is, maybe QAbstractItemModel, I haven't looked. QSqlTableModel does have an implementation.

    Good.

    dataChanged is only for updates. For insertion/deletion it's beginRemoveRows/rowsAboutToBeRemoved/rowsRemoved() etc. But QSqlTableModel does this for you. You don't have to raise signals, just ensure your view is properly connected to model.

    Got it, thanks.

    Why does it (apparently) not work? I don't know, but I do know you need to check the returns result of the _model->submitAll(); because maybe it's failing at database side.... When you write code like this, please look at return results and always check all of them, especially while developing/you don't know what is going on....

    Good shot, the problem is sumbitAll() that returns false.
    And inspecting the lastError() I found the root cause of my problem:

    QSqlError("19", "Unable to fetch row", "FOREIGN KEY constraint failed")

    It's correct, indeed.
    I didn't think about it becase I was afraid I didn't understand the documentation!



  • @Mark81
    Which is what I suspected would be the reason :) Just be aware: if you use a Qt function which returns a result, especially if it's calling some operation like "updating a database", when you first read the documentation to use it put it code to capture/test the result! :) I can see you have then used the docs to call lastError(), which is excellent!



  • As a general rule, if you have naked statement that return a boolean and your code just assumes it returns true then it's a good idea to wrap it in Q_ASSUME(). This will trigger a debug assertion if the method actually returned false and does nothing in release mode.
    e.g. Q_ASSUME(_model->submitAll());



  • @Mark81
    And what @VRonin has written is certainly better then no test at all! However, to be clear, in a case like this where an operation could genuinely return false, you must/should not just do this, you must provide proper error handling. Otherwise it works fine in your own development tests, but silently fails and does not check when you send out your release code, and you/the user have no idea it did fail or why! You probably already know that, just saying for other readers....



  • @JonB said in Yet another QSqlTableModel removeRows issue:

    @Mark81
    And what @VRonin has written is certainly better then no test at all! However, to be clear, in a case like this where an operation could genuinely return false, you must/should not just do this, you must provide proper error handling. Otherwise it works fine in your own development tests, but silently fails and does not check when you send out your release code, and you/the user have no idea it did fail or why! You probably already know that, just saying for other readers....

    Yes of course. As said I was a step before that - due to the doubts on the docs.
    Now, I've already connected a signal to show an error message to the user.


Log in to reply