#(58):编辑数据库外键
前面几章我们介绍了如何对数据库进行操作以及如何使用图形界面展示数据库数据。本章我们将介绍如何对数据库的数据进行编辑。当然,我们可以选择直接使用 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);
~~~
这段代码和我们前面见到的没有什么区别。我们可以将其补充完整后运行一下看看:
![](https://box.kancloud.cn/2015-12-29_5682326e0020e.png)
注意外键部分:City 一列仅显示出了我们保存的外键。如果我们使用`QSqlQuery`,这些都不是问题,我们可以将外键信息放在一个 SQL 语句中 SELECT 出来。但是,我们不想使用`QSqlQuery`,那么现在可以使用另外的一个模型:`QSqlRelationalTableModel`。`QSqlRelationalTableModel`与`QSqlTableModel`十分类似,可以为一个数据库表提供可编辑的数据模型,同时带有外键的支持。下面我们修改一下我们的代码:
~~~
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()`语句则提供了一种用于编辑外键的方式。运行一下程序看看效果:
[![](https://box.kancloud.cn/2015-12-29_5682326e0f583.png)](http://files.devbean.net/images/2013/07/sql-data-2.png)
此时,我们的外键列已经显示为 city 表的 name 字段的实际值。同时在编辑时,系统会自动成为一个`QComboBox`供我们选择。当然,我们需要自己将选择的外键值保存到实际记录中,这部分我们前面已经有所了解。
- (1)序
- (2)Qt 简介
- (3)Hello, world!
- (4)信号槽
- (5)自定义信号槽
- (6)Qt 模块简介
- (7)MainWindow 简介
- (8)添加动作
- (9)资源文件
- (10)对象模型
- (11)布局管理器
- (12)菜单栏、工具栏和状态栏
- (13)对话框简介
- (14)对话框数据传递
- (15)标准对话框 QMessageBox
- (16)深入 Qt5 信号槽新语法
- (17)文件对话框
- (18)事件
- (19)事件的接受与忽略
- (21)事件过滤器
- (22)事件总结
- (23)自定义事件
- (24)Qt 绘制系统简介
- (25)画刷和画笔
- (26)反走样
- (27)渐变
- (28)坐标系统
- (29)绘制设备
- (30)Graphics View Framework
- (31)贪吃蛇游戏(1)
- (32)贪吃蛇游戏(2)
- (33)贪吃蛇游戏(3)
- (34)贪吃蛇游戏(4)
- (35)文件
- (36)二进制文件读写
- (37)文本文件读写
- (38)存储容器
- (39)遍历容器
- (40)隐式数据共享
- (41)model/view 架构
- (42)QListWidget、QTreeWidget 和 QTableWidget
- (43)QStringListModel
- (44)QFileSystemModel
- (45)模型
- (46)视图和委托
- (47)视图选择
- (48)QSortFilterProxyModel
- (49)自定义只读模型
- (50)自定义可编辑模型
- (51)布尔表达式树模型
- (52)使用拖放
- (53)自定义拖放数据
- (54)剪贴板
- (55)数据库操作
- (56)使用模型操作数据库
- (57)可视化显示数据库数据
- (58)编辑数据库外键
- (59)使用流处理 XML
- (60)使用 DOM 处理 XML
- (61)使用 SAX 处理 XML
- (62)保存 XML
- (63)使用 QJson 处理 JSON
- (64)使用 QJsonDocument 处理 JSON
- (65)访问网络(1)
- (66)访问网络(2)
- (67)访问网络(3)
- (68)访问网络(4)
- (69)进程
- (70)进程间通信
- (71)线程简介
- (72)线程和事件循环
- (73)Qt 线程相关类
- (74)线程和 QObject
- (75)线程总结
- (76)QML 和 QtQuick 2
- (77)QML 语法
- (78)QML 基本元素
- (79)QML 组件
- (80)定位器
- (81)元素布局
- (82)输入元素
- (83)Qt Quick Controls
- (84)Repeater
- (85)动态视图
- (86)视图代理
- (87)模型-视图高级技术
- (88)Canvas
- (89)Canvas(续)