#(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);
~~~
這段代碼和我們前面見到的沒有什么區別。我們可以將其補充完整后運行一下看看:

注意外鍵部分: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()`語句則提供了一種用于編輯外鍵的方式。運行一下程序看看效果:
[](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(續)