Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
qt在一个事务中同时编辑多个QSqlTableModels_Qt_Postgresql_Transactions_Qsqltablemodel - Fatal编程技术网

qt在一个事务中同时编辑多个QSqlTableModels

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

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

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

  • 承包商(主表)-映射到“个人数据”部分
  • 联系人(具有contractors.ID的外键)
  • 地址(具有contractors.ID的外键)
因此,在我的window类中,我有3个主要模型(+2个代理模型,用于转换“个人数据”和“地址数据”部分中的表)。我使用
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语言编写的函数。它在开始和结束之间有一个事务。如果它在代码的某个点出错,那么它将完美地回滚所有数据

你现在做的不是一个好的设计,