PostgreSQL 9.3 データベースを使用する Qt アプリケーションにウィンドウがあります。ウィンドウは、新しいデータを表示、編集、および挿入するために使用されるフォームです。次のようになります。
そのビューには3つのSQLテーブルからのデータがあります。テーブルは外部キーに関連付けられています。
- 請負業者 (メイン テーブル) - 「個人データ」セクションにマッピング
- 連絡先 (contractors.ID への外部キーがあります)
- アドレス (contractors.ID への外部キーがあります)
したがって、私のウィンドウのクラスには3つのメインモデルがあります(+「個人データ」セクションと「アドレスデータ」セクションにテーブルを転置するための2つのプロキシモデル)。QSqlTableModel
これらのセクションと、 contactData セクションに使用しQSqlRelationalTableModel
ます。そのウィンドウを「通常」(一部の請負業者を表示するために)開くときは、単に請負業者の ID をコンストラクタに渡し、それを適切な変数に保存します。QSqlTableModel::setFilter(const QString & filter)
また、モデルごとにメソッドを呼び出し、適切なフィルタリングを設定します。そのウィンドウを「新規追加」モードで開くと、「-1」または「0」の値を ID 変数に渡すだけなので、データがモデルにロードされません。3 つのモデルすべてにQSqlTableModel::OnManualSubmit
editStrategyがあります。データを保存すると (適切なボタンをクリックしてトリガーされます)、トランザクションを開始します。そして、モデルを 1 つずつ提出します。personalData
挿入後にモデルの PK を取得する必要があるため (他のモデルの FK フィールドに設定するため)、モデルが最初に送信されます。モデルの送信が失敗した場合、QSqlError コンテンツを含む messageBox を表示し、トランザクションをロールバックしますメソッドから戻ります。処理中の最初のモデルでエラーが発生した場合、何も挿入されていないので問題ありません。しかし、最初のモデルが保存されたが、2 番目または 3 番目のモデルが失敗した場合、少し問題があります。そのため、前と同じようにトランザクションをロールバックし、関数から戻ります。しかし、データを修正して再度送信した後、ロールバックがあったことを認識せず、データを再度挿入する必要があるため、最初のモデルは送信しようとしません。そのようなモデルを再度提出する必要があることを通知するには、どうすればよいでしょうか? 現時点では、次のようなものになりました。
void kontrahenciSubWin::on_btnContractorAdd_clicked() {
//QStringList errorList; // when error occurs in one model - whole transacion gets broken, so no need for a list
QString error;
QSqlDatabase db = QSqlDatabase::database();
//backup the data - in case something fails and we have to rollback the transaction
QSqlRecord personalDataModelrec = personalDataModel->record(0); // always one row. will get erased by SubmitAll, as no filter is set, because I don't have its ID.
QList<QSqlRecord> contactDataModelRecList;
for (int i = 0 ; i< contactDataModel->rowCount(); i++) {
contactDataModelRecList.append( contactDataModel->record(i) );
}
QList<QSqlRecord> addressDataModelRecList;
for (int i = 0 ; i< addressDataModel->rowCount(); i++) {
addressDataModelRecList.append( addressDataModel->record(i) );
}
db.transaction();
if ( personalDataModel->isDirty() && error.isEmpty() ) {
if (!personalDataModel->submitAll()) //submitAll calls select() on the model, which destroys the data as the filter is invalid ("where ID = -1")
//errorList.append( personalDataModel->lastError().databaseText() );
error = personalDataModel->lastError().databaseText();
else {
kontrahentid = personalDataModel->query().lastInsertId().toInt(); //only here can I fetch ID
setFilter(ALL); //and pass it to the models
}
}
if ( contactDataModel->isDirty() && error.isEmpty() )
if (!contactDataModel->submitAll()) //slot on_contactDataModel_beforeInsert() sets FK field
//errorList.append( contactDataModel->lastError().databaseText() );
error = contactDataModel->lastError().databaseText();
if ( addressDataModel->isDirty() && error.isEmpty() )
if (!addressDataModel->submitAll()) //slot on_addressDataModel_beforeInsert() sets FK field
//errorList.append( addressDataModel->lastError().databaseText() );
error = addressDataModel->lastError().databaseText();
//if (!errorList.isEmpty()) {
// QMessageBox::critical(this, tr("Data was not saved!"), tr("The following errors occured:") + " \n" + errorList.join("\n"));
if (!error.isEmpty()) {
QMessageBox::critical(this, tr("Data was not saved!"), tr("The following errors occured:") + " \n" + error);
db.rollback();
personalDataModel->clear();
contactDataModel->clear();
addressDataModel->clear();
initModel(ALL); //re-init models: set table and so on.
//re-add data to the models - backup comes handy
personalDataModel->insertRecord(-1, personalDataModelrec);
for (QList<QSqlRecord>::iterator it = contactDataModelRecList.begin(); it != contactDataModelRecList.end(); it++) {
contactDataModel->insertRecord(-1, *it);
}
for (QList<QSqlRecord>::iterator it = addressDataModelRecList.begin(); it != addressDataModelRecList.end(); it++) {
addressDataModel->insertRecord(-1, *it);
}
return;
}
db.commit();
isInEditMode = false;
handleGUIOnEditModeChange();
}
誰かがより良いアイデアを持っていますか? レコードを挿入する前に、レコードのバックアップを省略できるかどうかは疑問です。しかし、それらをモデルに「再追加」するためのより良い方法があるでしょうか? "setRecord"
、と"remoweRows" & "insertRecord"
コンボを使おうとしましたが、うまくいきませんでした。モデル全体をリセットするのが最も簡単なようです(クリアするとテーブル、フィルター、ソート、その他すべてが失われるため、再初期化するだけで済みます)