QSqlTableModel.insertRecord()报错"No Fields to update"解决记录 && QField构造

发布时间 2023-09-14 19:42:48作者: 凡璞

问题的出现

当我想向一个Table中插入一条记录时,我本能的想的是:QSqlTableModel是由一条一条的Record组成的,那么我先创建一个Record,并且赋予对应的值,然后再使用QSqlTableModel::insertRecord()插入就好了,代码如下:

QSqlRecord rcd;
rcd.remove(model->fieldIndex("id"));
rcd.setValue("name", "upName");
rcd.setValue("platform", "Bilibili");
rcd.setValue("level", "Unknow");
auto status = model->insertRecord(-1, rcd);
if (status) {
    model->submitAll();
} else {
    qDebug() << "Last Error: " << model->lastError().text();
}

上述代码中model就是一个QSqlTableModel实例,有5个字段,分别是:id、name、platform、level、win_rate。(可以不用知晓其含义)
其中id是自增字段,level和win_rate都是可以为null的字段,name和platform是不可以为null的字段。
因为id是自增的,所以需要删除(网上查到的,事实也是如此)

执行输出:No Fields to update

问题的解决

查阅了很久发现有人这么写:

QSqlRecord rcd = model->record();
rcd.remove(model->fieldIndex("id"));
rcd.setValue("name", "upName");
rcd.setValue("platform", "Bilibili");
rcd.setValue("level", "Unknow");
auto status = model->insertRecord(-1, rcd);
if (status) {
    model->submitAll();
} else {
    qDebug() << "Last Error: " << model->lastError().text();
}

这个record是从model这里获取的,而不是自己创建的,试了之后发现成功了。
待了解了下面之后还有另一种办法来解决

问题的起因

如果按照第一种写法,之后再输出一下QSqlRecord,可以观察到结果为:QSqlRecord(0)
而如果按照第二种写法,之后再输出一下QSqlRecord,可以观察到结果为:

QSqlRecord(4)
 0: QSqlField("name", QString, tableName: "up_info", length: 64, generated: yes, typeID: 1043, autoValue: false, readOnly: false) "upName" 
 1: QSqlField("platform", QString, tableName: "up_info", length: 64, generated: yes, typeID: 1043, autoValue: false, readOnly: false) "Bilibili" 
 2: QSqlField("level", QString, tableName: "up_info", length: 64, generated: yes, typeID: 1043, autoValue: false, readOnly: false) "Unknow" 
 3: QSqlField("win_rate", double, tableName: "up_info", length: 4, generated: yes, typeID: 700, autoValue: false, readOnly: false) "0"

可以发现,第一种写法,QSqlRecord里面什么都没有。查看了文档发现:If the field does not exist, nothing happens
所以可以推测出:QSqlRecord::setValue()并不会增加field。而使用model.record(),里面是带field的。


经过进一步的查阅资料有以下总结:

  1. 可以简单的认为QSqlRecord是由多个QSqlField组成的一个数据结构。当QSqlRecordrd执行的操作与field相关时,如果Field没有存在,nothing happen。
  2. 使用QSqlTableModel向数据表中插入一条记录,可以先使用model.record()获取一个带有该表所有字段信息的记录,再修改字段内容再insert。这样比较方便
  3. 如果表中某个字段是自增的,那么QSqlRecord中需要移除该字段
  4. 使用QSqlRecord创建的记录也是可以插入的到表中的,可以使用QSqlRecord::append()方法先添加字段,再进行改变,再插入,相对麻烦。

PS:QSqlField构造有点坑,先看构造函数:
[explicit, since 6.0] QSqlField::QSqlField(const QString &fieldName = QString(), QMetaType type = QMetaType(), const QString &table = QString())
Qt6.0改版的QField构造函数。(网上查的好多都是以前的写法,直接报错)
坑就在指定字段类型这里,以前的写法是QVariant::String,已经被弃用了,本以为是用QMetaType::QString或者QMetaType::type::QString,结果还是错误
直到看到了官方的写法QMeta::fromType<QString>(),只有这么写才行。(麻烦)