Использование классов SQL-модели
Помимо QSqlQuery, Qt предлагает три класса более высокого уровня для доступа к базам данных. Эти классы — QSqlQueryModel, QSqlTableModel и QSqlRelationalTableModel.
| QSqlQueryModel | Модель только для чтения, основанная на произвольном SQL-запросе. |
| QSqlTableModel | Модель чтения и записи, работающая с одной таблицей. |
| QSqlRelationalTableModel | Подкласс QSqlTableModel с поддержкой внешних ключей. |
Эти классы наследуются от QAbstractTableModel (который, в свою очередь, наследуется от QAbstractItemModel) и упрощают представление данных из базы данных в классе представления элементов, таком как QListView и QTableView. Это подробно описано в разделе Представление данных в представлении таблицы.
Другое преимущество использования этих классов заключается в том, что ваш код легче адаптировать к другим источникам данных. Например, если вы используете QSqlTableModel, а затем решаете использовать XML-файлы для хранения данных вместо базы данных, это по существу просто вопрос замены одной модели данных на другую.
Модель SQL-запроса
QSqlQueryModel предлагает модель только для чтения, основанную на SQL-запросе.
Пример:
QSqlQueryModel model;
model.setQuery("SELECT * FROM employee");
for (int i = 0; i < model.rowCount(); ++i) {
int id = model.record(i).value("id").toInt();
QString name = model.record(i).value("name").toString();
qDebug() << id << name;
} После установки запроса с помощью QSqlQueryModel::setQuery() вы можете использовать QSqlQueryModel::record(int) для доступа к отдельным записям. Вы также можете использовать QSqlQueryModel::data() и любые другие функции, унаследованные от QAbstractItemModel.
Также есть перегрузка setQuery(), которая принимает объект QSqlQuery и работает с его набором результатов. Это позволяет использовать любые функции QSqlQuery для настройки запроса (например, подготовленные запросы).
Модель SQL-таблицы
QSqlTableModel предлагает модель чтения и записи, которая работает с одной SQL-таблицей за раз.
Пример:
QSqlTableModel model;
model.setTable("employee");
model.setFilter("salary > 50000");
model.setSort(2, Qt::DescendingOrder);
model.select();
for (int i = 0; i < model.rowCount(); ++i) {
QString name = model.record(i).value("name").toString();
int salary = model.record(i).value("salary").toInt();
qDebug() << name << salary;
} QSqlTableModel — это высокоуровневая альтернатива QSqlQuery для навигации и изменения отдельных SQL-таблиц. Как правило, это приводит к меньшему объёму кода и не требует знания синтаксиса SQL.
Используйте QSqlTableModel::record() для извлечения строки в таблице и QSqlTableModel::setRecord() для изменения строки. Например, следующий код увеличит зарплату каждого сотрудника на 10 процентов:
for (int i = 0; i < model.rowCount(); ++i) {
QSqlRecord record = model.record(i);
double salary = record.value("salary").toInt();
salary *= 1.1;
record.setValue("salary", salary);
model.setRecord(i, record);
}
model.submitAll(); Вы также можете использовать QSqlTableModel::data() и QSqlTableModel::setData(), которые унаследованы от QAbstractItemModel, для доступа к данным. Например, вот как обновить запись с помощью setData():
model.setData(model.index(row, column), 75000);
model.submitAll(); Вот как вставить строку и заполнить её:
model.insertRows(row, 1);
model.setData(model.index(row, 0), 1013);
model.setData(model.index(row, 1), "Peter Gordon");
model.setData(model.index(row, 2), 68500);
model.submitAll(); Вот как удалить пять последовательных строк:
model.removeRows(row, 5);
model.submitAll(); Первый аргумент функции QSqlTableModel::removeRows() — индекс первой строки для удаления.
Когда вы закончите изменение записи, всегда вызывайте QSqlTableModel::submitAll(), чтобы убедиться, что изменения запишутся в базу данных.
Необходимость и момент вызова submitAll() зависят от стратегии редактирования таблицы edit strategy. По умолчанию используется стратегия QSqlTableModel::OnRowChange, которая определяет, что ожидаемые изменения применяются к базе данных, когда пользователь выбирает другую строку. Другие стратегии — QSqlTableModel::OnManualSubmit (все изменения кэшируются в модели до вызова submitAll()) и QSqlTableModel::OnFieldChange (никаких изменений не кэшируется). Они в основном полезны, когда QSqlTableModel используется с представлением.
QSqlTableModel::OnFieldChange похоже обещает, что вам никогда не нужно явно вызывать submitAll(). Однако есть две ловушки:
- Без кэширования производительность может значительно снизиться.
- Если вы изменяете первичный ключ, запись может быть потеряна, пока вы пытаетесь её заполнить.
Модель SQL-связанной таблицы
QSqlRelationalTableModel расширяет QSqlTableModel для предоставления поддержки внешних ключей. Внешний ключ — это отображение 1-к-1 между полем в одной таблице и полем первичного ключа другой таблицы. Например, если в таблице book есть поле, называемое authorid, которое ссылается на поле id таблицы авторов, мы говорим, что authorid является внешним ключом.
На левом снимке экрана показана обычная QSqlTableModel в QTableView. Внешние ключи (city и country) не разрешаются в удобочитаемые значения. На снимке экрана справа показана QSqlRelationalTableModel, где внешние ключи разрешены в удобочитаемые текстовые строки.
Следующий фрагмент кода показывает, как была настроена QSqlRelationalTableModel:
model->setTable("employee");
model->setRelation(2, QSqlRelation("city", "id", "name"));
model->setRelation(3, QSqlRelation("country", "id", "name")); Подробности см. в документации QSqlRelationalTableModel.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.0/sql-model.html