首页 Qt 学习之路 2 Qt 学习之路 2(58):编辑数据库外键

Qt 学习之路 2(58):编辑数据库外键

13 4

前面几章我们介绍了如何对数据库进行操作以及如何使用图形界面展示数据库数据。本章我们将介绍如何对数据库的数据进行编辑。当然,我们可以选择直接使用 SQL 语句进行更新,这一点同前面所说的 model/view 的编辑没有什么区别。除此之外,Qt 还为图形界面提供了更方便的展示并编辑的功能。

普通数据的编辑很简单,这里不再赘述。不过,我们通常会遇到多个表之间存在关联的情况。首先我们要提供一个 city 表:

CREATE TABLE city (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR);

INSERT INTO city (name) VALUES ('Beijing');
INSERT INTO city (name) VALUES ('Shanghai');
INSERT INTO city (name) VALUES ('Nanjing');
INSERT INTO city (name) VALUES ('Tianjin');
INSERT INTO city (name) VALUES ('Wuhan');
INSERT INTO city (name) VALUES ('Hangzhou');
INSERT INTO city (name) VALUES ('Suzhou');
INSERT INTO city (name) VALUES ('Guangzhou');

由于 city 表是一个参数表,所以我们直接将所需要的城市名称直接插入到表中。接下来我们创建 student 表,并且使用外键连接 city 表:

CREATE TABLE student (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR,
    age INTEGER,
    address INTEGER,
    FOREIGN KEY(address) REFERENCES city(id));

我们重新创建 student 表(如果你使用的 RDBMS 支持 ALTER TABLE 语句直接修改表结构,就不需要重新创建了;否则的话只能先删除旧的表,再创建新的表,例如 sqlite)。

这里需要注意一点,如果此时我们在 Qt 中直接使用

INSERT INTO student (name, age, address) VALUES ('Tom', 24, 100);

语句,尽管我们的 city 中没有 ID 为 100 的记录,但还是是可以成功插入的。这是因为虽然 Qt 中的 sqlite 使用的是支持外键的 sqlite3,但 Qt 将外键屏蔽掉了。为了启用外键,我们需要首先使用QSqlQuery执行:

PRAGMA foreign_keys = ON;

然后就会发现这条语句不能成功插入了。接下来我们插入一些正常的数据:

INSERT INTO student (name, age, address) VALUES ('Tom', 20, 2);
INSERT INTO student (name, age, address) VALUES ('Jack', 23, 1);
INSERT INTO student (name, age, address) VALUES ('Jane', 22, 4);
INSERT INTO student (name, age, address) VALUES ('Jerry', 25, 5);

下面,我们使用 model/view 方式来显示数据:

QSqlTableModel *model = new QSqlTableModel(this);
model->setTable("student");
model->setSort(ColumnID_Name, Qt::AscendingOrder);
model->setHeaderData(ColumnID_Name, Qt::Horizontal, "Name");
model->setHeaderData(ColumnID_Age, Qt::Horizontal, "Age");
model->setHeaderData(ColumnID_City, Qt::Horizontal, "City");
model->select();

QTableView *view = new QTableView(this);
view->setModel(model);
view->setSelectionMode(QAbstractItemView::SingleSelection);
view->setSelectionBehavior(QAbstractItemView::SelectRows);
view->resizeColumnsToContents();

QHeaderView *header = view->horizontalHeader();
header->setStretchLastSection(true);

这段代码和我们前面见到的没有什么区别。我们可以将其补充完整后运行一下看看:

带有外键的数据库数据的显示

注意外键部分:City 一列仅显示出了我们保存的外键。如果我们使用QSqlQuery,这些都不是问题,我们可以将外键信息放在一个 SQL 语句中 SELECT 出来。但是,我们不想使用QSqlQuery,那么现在可以使用另外的一个模型:QSqlRelationalTableModelQSqlRelationalTableModelQSqlTableModel十分类似,可以为一个数据库表提供可编辑的数据模型,同时带有外键的支持。下面我们修改一下我们的代码:

QSqlRelationalTableModel *model = new QSqlRelationalTableModel(this);
model->setTable("student");
model->setSort(ColumnID_Name, Qt::AscendingOrder);
model->setHeaderData(ColumnID_Name, Qt::Horizontal, "Name");
model->setHeaderData(ColumnID_Age, Qt::Horizontal, "Age");
model->setHeaderData(ColumnID_City, Qt::Horizontal, "City");
model->setRelation(ColumnID_City, QSqlRelation("city", "id", "name"));
model->select();

QTableView *view = new QTableView(this);
view->setModel(model);
view->setSelectionMode(QAbstractItemView::SingleSelection);
view->setSelectionBehavior(QAbstractItemView::SelectRows);
view->resizeColumnsToContents();
view->setItemDelegate(new QSqlRelationalDelegate(view));

QHeaderView *header = view->horizontalHeader();
header->setStretchLastSection(true);

这段代码同前面的几乎一样。我们首先创建一个QSqlRelationalTableModel对象。注意,这里我们有一个setRelation()函数的调用。该语句说明,我们将第ColumnID_City列作为外键,参照于 city 表的 id 字段,使用 name 进行显示。另外的setItemDelegate()语句则提供了一种用于编辑外键的方式。运行一下程序看看效果:

直接显示外键
此时,我们的外键列已经显示为 city 表的 name 字段的实际值。同时在编辑时,系统会自动成为一个QComboBox供我们选择。当然,我们需要自己将选择的外键值保存到实际记录中,这部分我们前面已经有所了解。

13 评论

枫亦 2013年7月16日 - 16:10

请教博主一个问题,为什么我的qt不支持 accessibleName()方法,而这个方法明明就是QWidget的一个方法,难道是编译qt源码是把这个功能关闭了?博主如果知道的话,告诉一声,感激不尽!

回复
豆子 2013年7月17日 - 15:26

这个不大清楚,应该不会发生这种问题吧,是不是哪里有错误?

回复
andmoe 2013年8月14日 - 12:53

🙁 为啥在win8上开发的Qt5程序,在XP、2003、win7都不能运行呢?
在XP上重新编译,换台机子又不能运行了;
我已经安装了从vc2005到vc212的所有运行库了!

回复
豆子 2013年8月15日 - 09:03

理论上是没有问题的,不知道可能哪里出错了,具体是什么错误呢?

回复
andmoe 2013年8月15日 - 09:05

🙁 提示的就是那种运行时错误

回复
豆子 2013年8月16日 - 17:26

运行时错误有很多种,入口点错误、dll 链接库错误,不知道你遇到的哪种?

回复
andmoe 2013年8月17日 - 09:25

http://qt-project.org/doc/qt-5.0/qtdoc/deployment-windows.html

google了半天,终于找到了这篇!!!
楼主没遇到这种问题吗?
在本机上能运行,发布到其他机子上绝对不能运行!!

gameboy031 2013年9月16日 - 11:45

你发布的时候,连同QT安装目录下的platforms文件夹拷贝了没有?

回复
QT2012 2014年5月9日 - 11:03

外键列已经显示为 city 表的 name 字段的实际值,但修改后又显示ID字段值。

回复
豆子 2014年5月9日 - 23:16

因为外键是一次绑定的,如果进行修改,要重新使用外键进行查询。

回复
rainc 2014年6月19日 - 22:10

具体怎么理解,不是很理解。既然修改后又显示ID字段值,那有什么用。
如果进行修改,要重新使用外键进行查询,这个要怎么做,不是很明白

回复
bin 2015年5月8日 - 22:25

刚学QT,也遇见如上问题,向楼主求教解决方法

回复
豆子 2015年6月3日 - 11:35

可以尝试调用 model->setEditStrategy(QSqlTableModel::OnManualSubmit)

回复

回复 andmoe 取消回复

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2