除了QSqlQuery,Qt提供了3個高級類用於訪問數據庫。這些類是QSqlQueryModel、QSqlTableModel和QSqlRelationalTableModel。
這些類是由QAbstractTableModel(繼承自QAbstractItemModel)驅動並且它通過一個條目視圖類(比如QListView和QTableView)使得表示數據庫的數據更加簡單。這個詳細介紹在“用一個表視圖表示數據”一節。
使用這些類的另外一個好處是它使得你的代碼能夠更容易適用於其他數據源。例如,如果你使用的是QSqlTableModel,之后你打算使用XML文件來替換數據庫存儲數據,那么這個僅僅是簡單地用一個數據模型替換另一個數據模型的問題。
SQL查詢模型
QSqlQueryModel提供一個基於SQL查詢的只讀模型。例如:
1 QSqlQueryModel model; 2 model.setQuery("SELECT * FROM employee"); 3 4 for (int i = 0; i < model.rowCount(); ++i) { 5 int id = model.record(i).value("id").toInt(); 6 QString name = model.record(i).value("name").toString(); 7 qDebug() << id << name; 8 }
在使用QSqlQueryModel::setQuery()設置好查詢之后,你可以使用QSqlQueryModel::record(int)來訪問單個記錄。你也可以使用QSqlQueryModel::data()和其他任何繼承自QAbstractItemModel的函數。
還有一個重載的setQuery()方法,它帶有一個QSqlQuery對象並且在它的結果集中進行操作。它使得你可以使用QSqlQuery的任意特性來設置查詢(例如,prepared queries)。
SQL表模型
QSqlTableModel提供一個一次只能對一個SQL表進行操作的可讀可寫模型。例如:
1 QSqlTableModel model; 2 model.setTable("employee"); 3 model.setFilter("salary > 50000"); 4 model.setSort(2, Qt::DescendingOrder); 5 model.select(); 6 7 for (int i = 0; i < model.rowCount(); ++i) { 8 QString name = model.record(i).value("name").toString(); 9 int salary = model.record(i).value("salary").toInt(); 10 qDebug() << name << salary; 11 }
QSqlTableModel是一個高級的可替代QSqlQuery的模型,可以用於瀏覽和修改單個SQL表。它典型的優點是只需要少量的代碼並且不需要了解SQL語法。
使用QSqlTableModel::record()來檢索表中的一行,然后使用QSqlTableModel::setRecord()來修改這一行。例如,下面的代碼將對所有雇員的薪水增加10%。
1 for (int i = 0; i < model.rowCount(); ++i) { 2 QSqlRecord record = model.record(i); 3 double salary = record.value("salary").toInt(); 4 salary *= 1.1; 5 record.setValue("salary", salary); 6 model.setRecord(i, record); 7 } 8 model.submitAll();
你也可以使用繼承自QAbstractItemModel的方法QSqlTableModel::data()和QSqlTableModel::setData()來修改這些數據。例如,下面的代碼展示了怎樣用setData()更新一條記錄:
1 model.setData(model.index(row, column), 75000); 2 model.submitAll();
下面的代碼時怎樣插入一行:
1 model.insertRows(row, 1); 2 model.setData(model.index(row, 0), 1013); 3 model.setData(model.index(row, 1), "Peter Gordon"); 4 model.setData(model.index(row, 2), 68500); 5 model.submitAll();
下面的代碼時如何刪除5條連續行:
1 model.removeRows(row, 5); 2 model.submitAll();
QSqlTableModel::removeRows()的第一個參數是帶刪除的第一行的索引號。
當你完成了對記錄的修改,你總是需要調用QSqlTableModel::submitAll()來確保這些改動被寫入到數據庫中。
什么時候以及是否真的需要調用submitAll()實際上取決於表的編輯策略(edit strategy),默認的策略是QSqlTableModel::OnRowChange,也就是說當用戶選擇了另一個不同的行時上一行的改動將被應用到數據庫。其他的策略還包括QSqlTableModel::OnManualSubmit(所有改動將緩存在模型中,直到你調用submitAll()方法)和QSqlTableModel::OnFieldChange (不緩存改動)。這些策略在QSqlTableModel結合一個視圖一起使用時相當有用。
SQL關系表模型
QSqlRelationalTableModel擴展了QSqlTableModel來提供了對外鍵(foreign key)的支持。一個外鍵是一個表中的一個字段與另一個表中的主鍵(primary key)字段之間的一一映射。例如,如果一個book表中有一個authorid字段關聯到author表中的id字段,那么我們說authorid是一個外鍵。
The screenshot on the left shows a plain QSqlTableModel in a QTableView. Foreign keys (city and country) aren't resolved to human-readable values. The screenshot on the right shows a QSqlRelationalTableModel, with foreign keys resolved into human-readable text strings.
下面的代碼片段展示了如何設置QSqlRelationalTableModel:
1 model->setTable("employee"); 2 3 model->setRelation(2, QSqlRelation("city", "id", "name")); 4 model->setRelation(3, QSqlRelation("country", "id", "name"));
可以查閱QSqlRelationalTableModel文檔了解更多內容。