qt在一个事务中同时编辑多个QSqlTableModels
我在使用PostgreSQL 9.3数据库的Qt应用程序中有一个窗口。窗口是用于显示、编辑和插入新数据的窗体。t看起来是这样的: 在该视图中,我有来自3个sql表的数据。这些表与外键相关:qt在一个事务中同时编辑多个QSqlTableModels,qt,postgresql,transactions,qsqltablemodel,Qt,Postgresql,Transactions,Qsqltablemodel,我在使用PostgreSQL 9.3数据库的Qt应用程序中有一个窗口。窗口是用于显示、编辑和插入新数据的窗体。t看起来是这样的: 在该视图中,我有来自3个sql表的数据。这些表与外键相关: 承包商(主表)-映射到“个人数据”部分 联系人(具有contractors.ID的外键) 地址(具有contractors.ID的外键) 因此,在我的window类中,我有3个主要模型(+2个代理模型,用于转换“个人数据”和“地址数据”部分中的表)。我使用QSqlTableModel进行这些评估,使用Q
- 承包商(主表)-映射到“个人数据”部分
- 联系人(具有contractors.ID的外键)
- 地址(具有contractors.ID的外键)
QSqlTableModel
进行这些评估,使用QSqlRelationalTableModel
进行contactData部分。当“正常”打开该窗口(查看某个承包商)时,我只需将承包商ID传递给构造函数并将其存储在适当的变量中。另外,我为每个模型调用该方法,并设置适当的筛选。在“addnew”模式下打开该窗口时,我只需将“-1”或“0”值传递给ID变量,这样就不会将任何数据加载到模型中。
所有3个模型都有QSqlTableModel::OnManualSubmit
。保存数据时(通过单击适当的按钮触发),我启动一个事务。然后我一个接一个地提交模型personalData
model首先被提交,因为我需要在插入后获得它的PK(在其他型号的FK字段中设置)。
当模型提交失败时,我会显示一个带有QSqlError内容的messageBox,回滚事务,并从方法返回。
当我在处理的第一个模型上出错时-没有问题,因为没有插入任何内容。但是,当第一个模型被保存,但第二个或第三个模型失败时,就会出现一个小问题。所以我像以前一样回滚事务,并从函数返回。但是在更正数据并再次提交数据之后(第一个模型没有尝试提交),因为它不知道有回滚,所以需要再次插入数据。有什么好办法可以注意到这样一个模型,它需要再次提交?
当时我的结局是这样的:
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();
}
void kontrahenciSubWin::在合同上添加单击的内容(){
//QStringList errorList;//当一个模型中发生错误时,整个事务会被破坏,因此不需要列表
QString错误;
QSqlDatabase db=QSqlDatabase::database();
//备份数据-以防出现故障,我们必须回滚事务
QSqlRecord personalDataModelrec=personalDataModel->record(0);//始终为一行。将被SubmitAll删除,因为未设置任何筛选器,因为我没有其ID。
QList contactDataModelRecList;
对于(int i=0;irowCount();i++){
contactDataModelRecList.append(contactDataModel->record(i));
}
QList addressDataModelRecList;
对于(int i=0;irowCount();i++){
addressDataModelRecList.append(addressDataModel->record(i));
}
db.transaction();
if(personalDataModel->isDirty()&&error.isEmpty()){
如果(!personalDataModel->submitAll())//submitAll在模型上调用select(),这会破坏数据,因为筛选器无效(“其中ID=-1”)
//errorList.append(personalDataModel->lastError().databaseText());
error=personalDataModel->lastError().databaseText();
否则{
kontrahentid=personalDataModel->query().lastInsertId().toInt();//只有在这里才能获取ID
setFilter(ALL);//并将其传递给模型
}
}
if(contactDataModel->isDirty()&&error.isEmpty())
如果(!contactDataModel->submitAll())/\u contactDataModel\u beforeInsert()上的插槽设置FK字段
//errorList.append(contactDataModel->lastError().databaseText());
错误=contactDataModel->lastError().databaseText();
if(addressDataModel->isDirty()&&error.isEmpty())
如果(!addressDataModel->submitAll())/\u addressDataModel\u beforeInsert()上的插槽设置FK字段
//errorList.append(addressDataModel->lastError().databaseText());
error=addressDataModel->lastError().databaseText();
//如果(!errorList.isEmpty()){
//QMessageBox::critical(此,tr(“数据未保存!”),tr(“发生以下错误:”)+“\n”+errorList.join(“\n”));
如果(!error.isEmpty()){
QMessageBox::critical(这是tr(“数据未保存!”),tr(“发生了以下错误:)+“\n”+错误);
db.rollback();
personalDataModel->clear();
contactDataModel->clear();
addressDataModel->clear();
initModel(ALL);//重新初始化模型:set table等等。
//向模型中重新添加数据-备份很方便
personalDataModel->insertRecord(-1,personalDataModelrec);
对于(QList::iterator it=contactDataModelRecList.begin();it!=contactDataModelRecList.end();it++){
contactDataModel->insertRecord(-1,*it);
}
对于(QList::iterator it=addressDataModelRecList.begin();it!=addressDataModelRecList.end();it++){
addressDataModel->insertRecord(-1,*it);
}
返回;
}
db.commit();
isInEditMode=false;
handleGUIOnEditModeChange();
}
有人有更好的主意吗?我怀疑在尝试插入记录之前是否可以备份记录。但也许有更好的方法将它们“重新添加”到模型中?我尝试使用
“setRecord”
,和“remoweRows”和“insertRecord”
组合,但没有运气。重置整个模型似乎最简单(我只需要重新初始化它,因为它在清除时会丢失表、过滤器、排序和其他所有内容)我建议您使用用PLPGSQL语言编写的函数。它在开始和结束之间有一个事务。如果它在代码的某个点出错,那么它将完美地回滚所有数据
你现在做的不是一个好的设计,