私のクラス DataTable は QAbstractTableModel から派生しています。QSqlTableModel オブジェクトを内部で使用して、db テーブルからデータをフェッチします。これは、データベース内のすべての行のレコードを表します (より多くのことを行いますが、レコード数は常に db テーブル内の行数です)。
MySql では、私の DataTable::rowCount() 実装は QSqlTableModel で rowCount() を呼び出すだけで、うまく機能します。
SQLite を使用すると、db テーブルに 256 行を超える行がある場合、Qt の SQLite ドライバーは行数 256 を返すため、DataTable クラスも 256 を返しますが、これは間違っています。ドキュメントには、に電話するように指示されていますwhile (sql_model->canFetchMore()) sql_model->fetchMore();
。内部 QSqlTableModel が作成された直後に fetchMore() を呼び出すと、実際には次の rowCount() 呼び出しで正しい値が返されます。しかし、データベースで何かが変更されると (私のクラスは QSqlTableModel で insertRow() または setData() を呼び出します)、次の QSqlTableModel::rowCount() 呼び出しは再び 256 を返します。
データベースは、特定の QSqlTableModel オブジェクトを使用するクラスによってのみ変更されます (または、DataTable をモデルとして使用するビューが何かを更新する可能性があります)。したがって、データベースに行を挿入できる他のプロセスはありません。
では、いつ DataTable クラスが fetchMore() を呼び出して、rowCount() が常に実際の行数を返すようにすべきでしょうか?
私のクラスは、QSqlTableModel によって発行されたシグナルの一部を fetchMore() を呼び出すスロットに接続する必要があると考えていますが、それが適切で信頼できる方法であるかどうかはわかりません。
更新:
基本的な問題を示すコードを次に示します。
QSqlTableModel *model = new QSqlTableModel(0, database); //QSqlDatabase
model->setTable("tablename");
qDebug() << "0 row count" << model->rowCount(); //0 row count 0
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
model->select();
qDebug() << "1 row count" << model->rowCount(); //1 row count 256
while (model->canFetchMore()) model->fetchMore();
qDebug() << "2 row count" << model->rowCount(); //2 row count 1520
//... other methods ...
model->setData(model->index(0, 0), "TEST");
model->submitAll();
qDebug() << "3 row count" << model->rowCount(); //3 row count 256
while (model->canFetchMore()) model->fetchMore();
qDebug() << "4 row count" << model->rowCount(); //4 row count 1520
SQL モデルをロードした後、rowCount() は 256 (1) を返すため、fetchMore() を呼び出す必要があります。その後、rowCount() は実際の行数を返します。
その後、データが変更され、その後、rowCount() は再び 256 (3) を返します。
そのため、sql モデルに対するすべての書き込み操作の後に fetchMore() を呼び出す必要があるようです。しかし、この while/canFetchMore()/fetchMore() ループをモデルを変更するすべてのメソッドの最後に置くのではなく、beforeInsert(QSqlRecord&)、beforeUpdate(int, QSqlRecord&) を接続するだけで十分かどうか疑問に思っています。 beforeDelete(int) は、fetchAll()? を呼び出すスロットに通知しますか? これは信頼でき、適切でしょうか?
訂正: before* シグナルではなく (時期尚早)、おそらく layoutChanged()、dataChanged()、rowsInserted()、rowsRemoved()。
更新 2 :
SQL に関する注意: 理論的には別の SQL クエリをデータベースに送信できることはわかっていSELECT COUNT
ますが、これは質問の答えにはなりません。SQL を避けることができる限り、SQL は書きません。私の考えでは、このような SQL クエリを送信することは、オブジェクト指向の QAbstractTableModel クラスの目的に反しています。さらに、rowCount() は const (クエリを送信しないでください) であり、高速である必要があります。とにかく、これはrowCount()を修正しません。
fetchMore() を呼び出すスロットを関連するシグナル (上記参照) に接続し、 rowCount () ですべてがフェッチされたことをアサートすることになりました。
assert(!sql_model->canFetchMore())
これは、rowCount() が正しい行数カウントを失敗状態として報告できないためです。したがって、アサーションです。つまり、間違った行数を使用するよりも、アプリケーションをクラッシュさせたいと考えています。
それを dataChanged() シグナルに接続するだけでは(最初の回答で提案されているように: I would probably try to use dataChanged signal.
)十分ではありません。dataChanged(const QModelIndex&, const QModelIndex&)
、rowsInserted(const QModelIndex&, int, int)
、rowsRemoved(const QModelIndex&, int, int)
およびに接続しましたlayoutChanged()
。
動作しているように見えますが、アサーションはまだ失敗していません。
誰かがこれを明確に確認できる場合 (または、常に機能するとは限らない理由を説明する場合)、回答をいただければ幸いです。