Insert record into QSqlTableModel
-
@JonB For example, the tablemodel has 50 rows and the primary key is from 1 to 50. If you delete line 20, the number 20 will be missing from the primary key. If a row is inserted in line 20, the primary key will not generate the primary key 20, but will add the primary key 51 at the end.
-
void JCDemoDatabase::onRemoveClicked() { qDebug() << __FUNCTION__ << tableView->currentIndex().row(); int32_t currentRowIndex = tableView->currentIndex().row(); tableModel->database().transaction(); if (!tableModel->removeRow(currentRowIndex)) { qDebug() << __FUNCTION__ << 1 << "Error inserting record to the model"; qDebug() << __FUNCTION__ << 2 << tableModel->lastError().text(); } if (tableModel->submitAll()) { tableModel->database().commit(); } else { tableModel->database().rollback(); qDebug() << __FUNCTION__ << 3 << tableModel->lastError().text(); } // tableModel->select(); // tableView->setModel(tableModel); qDebug() << __FUNCTION__ << 4 << tableModel->rowCount(); }
-
@tovax said in Insert record into QSqlTableModel:
@JonB For example, the tablemodel has 50 rows and the primary key is from 1 to 50. If you delete line 20, the number 20 will be missing from the primary key. If a row is inserted in line 20, the primary key will not generate the primary key 20, but will add the primary key 51 at the end.
This is probably a true statement, but I don't know what you are asking.
If you have an auto-increment primary key in the backend database, and you delete a row, then left to its own devices the next record will not "fill" the gap, it will use the next highest available number. If in your code you attempt to tell it to use the missing number for its value on inserting a new record, then (I believe) some databases will respect that, some will ignore it and allocate the next number, and some will probably error with "duplicate key". If your database supports inserting a row with a PK in the "middle", it is your job in your code to calculate that missing number and pass it in your
INSERT
statement. The backend will not do that for you. And I don't see any indication you are doing that.Your Qt code does not know about this. I am not sure whether after
submitAll()
Qt automatically tries to re-read the record inserted/get its values from the backend and will see what it actually got or not. If necessary your commented-outtableModel->select();
can be issued to re-read what is actually there now.I do not understand what your question here is? You say nothing about whether you get any error messages, nothing about what you or do not want. And overall your question is about the "tableview", which I thought is what you were questioning, but now I wonder if you are just reporting it displays whatever is in the model? So if it gets the new highest number it will indeed appear at the end in the view.
-
@JonB Hi, thank you for your patience. My intention is to insert a record in the current row of tablemodel, but it is always appended to the end.
The relevant code is this sentence:tableModel->insertRecord(currentRowIndex, record)
That's what the help manual says:
bool QSqlTableModel::insertRecord(int row, const QSqlRecord &record) Inserts the record at position row. If row is negative, the record will be appended to the end.
But the test result is: no matter what the value of “row” is, record is always appended to the end.
-
@tovax
As I said, this may depend on when you do this with regard to when you submit your changes to the backend, which may cause the value to be altered. Print out what the value of the PK auto-increment is after you insert, or more to the point after you submit.Purely at a guess, comment out your
record.setGenerated(Table::PrimaryKey, true); // true
, and even yourrecord.field(Table::PrimaryKey).setAutoValue(true);
. Does this make a difference to whether it respects your value if you pass in a "missing" middle one? -
@JonB The test result is: Whether "setGenerated" and "setAutoValue" are commented out or not, the primary key is always 0 before insertion. I think that's why we can't meet our expectations.
So I'm confused about "setGenerated" and "setAutoValue", don't they mean automatic generation of primary keys? -
@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; }