Qt 如何使用QSqlQuery获取事务中先前插入的行的ID

Qt 如何使用QSqlQuery获取事务中先前插入的行的ID,qt,transactions,qtsql,Qt,Transactions,Qtsql,我试图获取事务范围内插入行的主键,因为我不想让数据库处于逻辑不一致的状态 我的问题是,我找不到一种方法来检索以前执行的查询的ID值,我想将其用于下一个insert查询。在事务生效时查询PostgreSQL数据库,在非外键表中不会显示任何结果(行尚未提交?)。我相信这是由于事务的隔离级别 下面是我试图对生产代码所做的操作,不过为了清晰起见,我稍微编辑了一下,并将其缩小为一个函数const int lastInsertId始终为0,在本上下文中,这意味着未找到任何值(从技术上讲,toInt()函数失

我试图获取事务范围内插入行的主键,因为我不想让数据库处于逻辑不一致的状态

我的问题是,我找不到一种方法来检索以前执行的查询的ID值,我想将其用于下一个insert查询。在事务生效时查询PostgreSQL数据库,在非外键表中不会显示任何结果(行尚未提交?)。我相信这是由于事务的隔离级别

下面是我试图对生产代码所做的操作,不过为了清晰起见,我稍微编辑了一下,并将其缩小为一个函数
const int lastInsertId
始终为0,在本上下文中,这意味着未找到任何值(从技术上讲,
toInt()
函数失败)。我尝试手动插入一个有效的非外键行,然后调用
LASTVAL()
,这将产生预期的结果—插入行的ID

那么,我做错了什么?我在这里遗漏了什么或误解了什么

void createEntityWithoutForiegnKeyConstraint(const QString &nameOfEntity)
{
  db_.transaction();

  QSqlQuery insertQuery(db_);
  insertQuery.prepare("INSERT INTO \"EntityWithoutForeignKey\" (\"name\") VALUES (:name);");

  insertQuery.bindValue(":name", nameOfEntity);
  execQuery(__LINE__, insertQuery);
  QSqlQuery lastIdQuery("SELECT LASTVAL();", db_); // auto executes
  const int lastInsertId = lastIdQuery.value(0).toInt();

  if (lastInsertId <= 0) // 0 is not a valid ID
    throw exception("Oh noes.");

  createEntityWithForeignKeyConstraint(lastInsertId, someData);

  if (!db_.commit())
    db_.rollback();
}
void createEntityWithOutOriengKeyConstraint(常量QString和实体名称)
{
db_.transaction();
QSqlQuery insertQuery(数据库);
准备(“插入到\“EntityWithoutForeignKey\”(\“name\”)值(:name);”);
insertQuery.bindValue(“:name”,实体名称);
execQuery(_行,插入查询);
QSqlQuery lastIdQuery(“SELECT LASTVAL();”,db_);//自动执行
const int lastInsertId=lastIdQuery.value(0.toInt();

如果(lastInsertId我意识到这是一个老问题,但在Qt5.10(可能更早)中,有一个函数
QSqlQuery::lastInsertId()
,可以在
QSqlQuery::exec()之后调用

如果您使用的是SQLite之类的数据库,它不支持
INSERT
语句中的
RETURNING
子句,那么它非常有用

用法大致如下:

QSqlQuery q;
q.prepare("INSERT INTO table_name VALUES(:some_column_name)");
q.bindValue(":some_column_name", "FooBar");
q.exec();

qDebug() << "Last ID was:" << q.lastInsertId();
qsqlqueryq;
q、 准备(“插入表名称值(:某些列名称)”);
q、 bindValue(“:某些列名称”、“FooBar”);
q、 exec();

qDebug()@Kasheen是完全正确的,但我想把重点放在一个你应该记住的重要方面:不要忘记将所有内容封装在一个事务中

为什么?如果使用生成的主键(使用
q.lastInsertId()
)进行第二次插入失败,则可以节省时间并避免数据库损坏

因此,您的插入应该如下所示(这基本上是@Kasheen的答案,并添加了一些内容):


@平均joe正确处理事务,但如果只查看解决方案,您可能会忘记它。

密切相关:同意;
INSERT…返回
在此处非常理想。有关详细信息,请参阅。确认从pgAdmin返回可用于测试插入,如插入到非ForeignKeyEntity(“id”、“name”)值中(默认设置为“teste”)返回“id”
。但是通过
QSqlQuery
,这不起作用,因此我在这里仍然需要指导。如何从查询对象检索该值。我必须为返回值或其他内容绑定一个变量吗?
insertQuery.record().indexOf(“id”);
返回0,根据Qt文档,这是一个有效的索引。我真的很慌乱。如果字段存在,为什么没有值?在获取值之前,您可能必须调用insertQuery.next()。
db_.transaction(); // Starts a transaction

QSqlQuery q;

// first insert
q.prepare("INSERT INTO table_name VALUES(:some_column_name)");
q.bindValue(":some_column_name", "FooBar");
q.exec();

auto pk == q.lastInsertId().toInt;

// second insert
q.prepare("INSERT INTO other_table VALUES(:other_column_name, :fk)");
q.bindValue(":other_column_name", "OtherText");
q.bindValue(":fk", pk);
q.exec();

db_.commit(); // Commits transaction