gpt4 book ai didi

qt多个QSqlTableModels在一个事务中一起编辑

转载 作者:行者123 更新时间:2023-11-29 13:28:57 25 4
gpt4 key购买 nike

我在使用 PostgreSQL 9.3 数据库的 Qt 应用程序中有一个窗口。窗口是用来显示、编辑和插入新数据的窗体。看起来像这样: enter image description here

我在该 View 中有来自 3 个 sql 表的数据。这些表与外键相关:

  • contractors(主表)- 映射到“个人数据”部分
  • 联系人(具有 contractors.ID 的外键)
  • 地址(具有指向 contractors.ID 的外键)

所以 - 在我的窗口类中,我有 3 个主要模型(+ 2 个代理模型用于转置“个人数据”和“地址数据”部分中的表格)。我将 QSqlTableModel 用于这些部分,将 QSqlRelationalTableModel 用于 contactData 部分。当“正常”打开那个窗口(查看一些承包商)时,我只是将承包商的 ID 传递给构造函数并将其存储在适当的变量中。另外,我调用 QSqlTableModel::​setFilter(const QString & filter)每个模型的方法,并设置适当的过滤。当以“添加新”模式打开该窗口时,我只是将“-1”或“0”值传递给 ID 变量,因此没有数据加载到模型中。所有 3 个模型都有 QSqlTableModel::OnManualSubmit editStrategy .保存数据时(通过单击适当的按钮触发),我开始交易。然后我一个一个地提交模型。 personalData 模型首先被提交,因为我需要在插入后获取它的 PK(以在其他模型的 FK 字段中设置)。当提交模型失败时,我会显示一个包含 QSqlError 内容的消息框,回滚事务 并从该方法返回。当我在处理第一个模型时出现错误 - 没问题,因为没有插入任何内容。但是当第一个模型被保存,但第二个或第三个模型失败时 - 有一个小问题。所以我像以前一样回滚事务,然后从函数返回。但是在更正数据并再次提交之后——第一个模型没有尝试提交——因为它不知道有回滚,需要再次插入数据。注意到这种需要再次提交的模型的好方法是什么?此刻我得到了这样的结果:

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" 组合,但没有成功。重置整个模型似乎最简单(我只需要重新初始化它,因为它在清除时会丢失表、过滤器、排序和其他所有内容)

最佳答案

我建议您使用以 PLPGSQL 语言编写的函数。它在 BEGIN 和 END 之间有一个事务。如果在代码的某个点出错,那么它会完美地回滚所有数据。

您现在所做的不是一个好的设计,因为您将对特定功能(回滚)的控制处理到与回滚相关的外部系统(它发生在数据库中)。外部系统不是为此而设计的,相反,数据库是为处理回滚和事务而创建和设计的。它非常擅长。在数据库外部重建和重新发明此功能非常复杂,会带来很多麻烦。您将永远无法获得与在数据库中使用函数时相同的完美回滚处理。

让每个系统做它能做的最好的事情。

我以前遇到过你的问题,并且在我的案例中使用 Hibernate 解决这个问题的思路相同。直到我放弃我的努力并重新评估情况。有三个团队致力于数据库的回滚机制:1. 编写数据库本身源代码的男男女女,2. 编写 Hibernate 代码的男男女女,以及3.我。第一个团队致力于创建良好的回滚机制。如果他们失败了,他们的产品就不好。他们成功了。第二个团队致力于创建良好的回滚机制。当他们的产品在非常复杂的情况下无法正常工作时,他们的产品并没有失败。最后一个团队,我,并没有专门解决这个问题。我是谁来编写一个更好的解决方案,而不是团队 2 或团队 1 的人基于团队 2 的工作而无法达到团队 1 的水平?那是我决定改用数据库函数的时候。

关于qt多个QSqlTableModels在一个事务中一起编辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28226321/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com