Insert record into QSqlTableModel
-
@tovax said in Insert record into QSqlTableModel:
So I'm confused about "setGenerated" and "setAutoValue", don't they mean automatic generation of primary keys?
@JonB When I manually set a non duplicate value for the primary key, the record can be correctly inserted into the current row.
Yes, they mean auto-generation. So they generate the next number, not some "middle" one! As you say, if you want to "force in" your own, missing number then you cannot ask it to auto-generate the value for you!
You can probably disable auto-generate, insert your explicit one, and then re-enable auto-generate from then on?
-
@tovax
I will say one thing: you should not really be trying to do this at all! You're not "supposed" to go back and re-insert auto-gen keys if you have deleted one.Imagine you have one million rows. One of them has a "gap". How are you going to find that gap one? If you have to do it client/Qt side, the only way is to read all one million into the client and iterate them to find any gap. Not a good idea! Even if you try to use server-side SQL code to avoid downloading them all, I don't think your SQL will offer any (efficient) way of discovering the gap. So maybe thing again....??
-
@tovax said in Insert record into QSqlTableModel:
How can I insert a record in the current row, please?
What do you mean? A record is a row. Do you want to update a row?
-
@tovax
Listen carefully! :) To emulate rows in Excel, you should not use any auto-incremented primary key in the database! That is not the way to do it, and leads to your "missing row" problem.Instead, you must your own "row number" integer variable as a column. But not auto-incremented. Instead, you must fill it with the desired row number. And if you insert a row you must write code to renumber all the subsequent ones to allow for this one to go in, and if you delete a row you must write code to decerment all the higher ones to close the gap.
Trust me :D
-
@JonB Thank you very much! According to your suggestion, I have implemented the insertion function. As you said, the primary key not auto-incremented, and renumber primary key before inserting.
Best regards!void JCDemoDatabase::onInsertClicked() { qDebug() << __FUNCTION__ << tableView->currentIndex().row(); // current row int32_t currentRowIndex = tableView->currentIndex().row(); // prepare insert primary key tableModel->database().transaction(); insertPrimaryKey(tableModel, currentRowIndex); // new record QSqlRecord record = tableModel->record(); for (int32_t columnIndex = Table::Field::Min; columnIndex <= Table::Field::Max; columnIndex++) { record.setValue(Table::FieldText[columnIndex], QString("---")); } record.setValue(Table::PrimaryKey, currentRowIndex + 1); // insert new record if (!tableModel->insertRecord(currentRowIndex, record)) { qDebug() << __FUNCTION__ << "Error 1: " << tableModel->lastError().text(); } // submit all if (tableModel->submitAll()) { tableModel->database().commit(); } else { tableModel->database().rollback(); qDebug() << __FUNCTION__ << "Error 2: " << tableModel->lastError().text(); } }
int32_t JCDemoDatabase::insertPrimaryKey(QSqlTableModel *model, int32_t row) { // TODO: invalid // model->record(rowIndex).setValue(Table::PrimaryKey, (rowIndex + 1)); // key int32_t oldMax = model->record(model->rowCount() - 1).value(Table::PrimaryKey).toInt(); int32_t newMax = model->rowCount() + 1; if (oldMax < newMax) { oldMax = newMax; } // backup for (int32_t rowIndex = 0; rowIndex < model->rowCount(); rowIndex++) { QSqlRecord record = model->record(rowIndex); record.setValue(Table::PrimaryKey, oldMax + 1 + rowIndex); model->setRecord(rowIndex, record); } if (model->submitAll()) { model->database().commit(); } else { model->database().rollback(); qDebug() << __FUNCTION__ << 1 << model->lastError().text(); } // less than "row" for (int32_t rowIndex = 0; rowIndex < row; rowIndex++) { QSqlRecord record = model->record(rowIndex); record.setValue(Table::PrimaryKey, rowIndex + 1); model->setRecord(rowIndex, record); } if (model->submitAll()) { model->database().commit(); } else { model->database().rollback(); qDebug() << __FUNCTION__ << 2 << model->lastError().text(); } // reserve row for currentRowIndex // greater than "row" for (int32_t rowIndex = row; rowIndex < model->rowCount(); rowIndex++) { QSqlRecord record = model->record(rowIndex); record.setValue(Table::PrimaryKey, rowIndex + 2); model->setRecord(rowIndex, record); } if (model->submitAll()) { model->database().commit(); } else { model->database().rollback(); qDebug() << __FUNCTION__ << 3 << model->lastError().text(); } return row + 1; }
-
@tovax
Hmm, I'm a bit worried about your algorithm. Depends how this works in your database, and how the updates/transactions work, but....I see when you insert you renumber upwards. If this is a unique/primary key, that will keep "bumping into" the number above which already exists (hasn't been renumbered yet). Which might error?
If it were me: to renumber for an insert I would start from the highest number, increment that, prodceed downward through the numbers. To renumber for a delete, I would start from one above the delete, decrement, then proceed upward till the last row. Makes sense?
Of course, your approach is incredibly slow (at least for a remote/full database, not just a local file) across a large number of rows. I take it you are not concerned about having a thousand or a million of them....?
-
A key in a db is there so it gets not reused. It's somehow contradicts the reason for a primary key... If a column with an id is deleted this id should not be used again. I also don't see why it should be needed in your case at all.
-
@Christian-Ehrlicher
(I believe) the reason is the OP is wanting to emulate "inserting a row of data in Excel table". So he wants a row number of some description to get the ordering. Which I have said he should implement himself, not make auto-increment do it. (He might still use an auto-inc for the PK to identify the row if he wishes, but a dedicated unique column for the ordered row number usage.) -
A PK is not to be used for ordering or something else.
-
@Christian-Ehrlicher
Um, that's what I've been saying.... Hence he needs something else for ordering.
TBH it's not even the PK which is at issue here, it's the auto-increment being unsuitable for OP's ordering. -
@JonB I'm not sure I understand your algorithm correctly.
int32_t JCDemoDatabase::insertPrimaryKey(QSqlTableModel *model, int32_t row) { int32_t keyMax = model->record(model->rowCount() - 1).value(Table::PrimaryKey).toInt(); // greater than "row" for (int32_t rowIndex = row; rowIndex < model->rowCount(); rowIndex++) { QSqlRecord record = model->record(rowIndex); record.setValue(Table::PrimaryKey, (keyMax + 2) + (rowIndex - row)); model->setRecord(rowIndex, record); } if (model->submitAll()) { model->database().commit(); } else { model->database().rollback(); qDebug() << __FUNCTION__ << 1 << model->lastError().text(); } return keyMax + 1; // reserve for insertion } int32_t JCDemoDatabase::removePrimaryKey(QSqlTableModel *model, int32_t row) { int32_t key = model->record(row).value(Table::PrimaryKey).toInt(); // less than "row" for (int32_t rowIndex = row - 1; rowIndex >= 0; rowIndex--) { QSqlRecord record = model->record(rowIndex); record.setValue(Table::PrimaryKey, (key - 1) + (rowIndex - (row - 1))); model->setRecord(rowIndex, record); } if (model->submitAll()) { model->database().commit(); } else { model->database().rollback(); qDebug() << __FUNCTION__ << 1 << model->lastError().text(); } return 0; }