Reputation: 2854
I have a problem with inserting new QSqlRecord to Postgresql database. Target table is defined as follows:
create table samochod(
samochod_id integer primary key default nextval('samochod_id_seq'),
marka varchar(30),
poj_silnika numeric,
typ_silnika silnik_typ,
liczba_osob smallint
);
And code of record insertion is:
QSqlRecord rec = model->record();
rec.setGenerated("samochod_id", false);
rec.setValue("marka", ui.brandEdit->text());
rec.setValue("poj_silnika", ui.volSpin->value());
rec.setValue("typ_silnika", ui.engineCombo->currentText());
rec.setValue("liczba_osob", ui.passengersSpin->value());
bool ok = model->insertRecord(-1,rec);
All I want to do is insert a new record, and make sql set its samochod_id
for me, but despite I set isGenerated
to false it crashes with message:
"ERROR: null value in column "samochod_id" violates not-null constraint
QPSQL: Unable to create query"
What should I do to make QSqlRecord leave generation of samochod_id
to database?
Upvotes: 3
Views: 4802
Reputation: 11
This is a known bug since Qt 4.8:
https://bugreports.qt-project.org/browse/QTBUG-23592
Upvotes: 1
Reputation: 4816
You can use removeColumn(int)
before QSqlRecord rec = model->record()
and it should work. If model
is associated to a view (a QTableView instance, for example), you'll be effectively hiding the samochod_id
column, though.
Try this:
// get the index of the id column
int colId = model.fieldIndex("samochod_id");
// remove the column from the model
model.removeColumn(colId);
QSqlRecord rec = model->record();
// rec.setGenerated("samochod_id", false); /// not needed anymore
rec.setValue("marka", ui.brandEdit->text());
rec.setValue("poj_silnika", ui.volSpin->value());
rec.setValue("typ_silnika", ui.engineCombo->currentText());
rec.setValue("liczba_osob", ui.passengersSpin->value());
bool ok = model->insertRecord(-1,rec);
I can understand why you prefer to insert records this way (avoid writing SQL manually).
I think using a QSqlTableModel
instance just for the purpose of inserting records is too expensive (models are complex beasts), so I prefer to use a plain QSqlQuery
. With this approach it is not necessary to instantiate multiple QSqlTableModel
s if you need to insert records in multiple tables in a transaction, a single QSqlQuery
is enough:
QSqlDatabase::database("defaultdb").transaction();
QSqlQuery query(QSqlDatabase::database("defaultdb"));
query.prepare(QString("INSERT INTO table1 (field1, field2) VALUES(?,?)"));
query.bindValue(0,aString);
query.bindValue(1,anotherString);
query.exec();
// insert in another table
query.exec(QString("INSERT INTO table2 (field1, field2) VALUES(...)");
bool ok = QSqlDatabase::database("defaultdb").commit();
query.finish();
if(!ok){
// do something
}
Upvotes: 3
Reputation: 2854
I have found a weird solution to this problem. Line:
rec.setGenerated("samochod_id", false);
int method above seemed to have no effect, but when I moved it to signal handler of my model, it started to work as expected:
CarsModel::CarsModel(QObject * parent, QSqlDatabase db)
: SqlModel(parent, db, "samochod")
{
engineTypes << "Diesel" << "Na gaz" << "Benzynowy" << "Elektryczny";
connect(this, SIGNAL(beforeInsert(QSqlRecord &)), this,
SLOT(beforeInsertRec(QSqlRecord &)));
}
void CarsModel::beforeInsertRec(QSqlRecord & rec){
rec.setGenerated(0, false);
}
Upvotes: 2
Reputation: 22925
I have no experience working with Qt, but I would recommend setting no value at all for the samochod_id
column.
On SQL
level this could look like this:
INSERT INTO samochod (marka, poj_silnika, poj_silnika, liczba_osob)
VALUES (...);
As you see, I just “ignore” samochod_id
column, letting PostgreSQL use the default value.
Upvotes: 0