Моя программа запрашивает у базы данных MariaDB некоторые данные и отображает их в экземпляре QTableView через подкласс QSqlQueryModel - я только что переопределил методы columnsCount(), headerData() и data(), чтобы получить модель, доступную только для чтения:
- дает постоянное число (запрос, используемый с этой моделью, всегда имеет постоянное количество столбцов в инструкции SELECT)
Код: Выделить всё
columnCount() - переопределен только для того, чтобы давать удобочитаемые имена столбцов.
Код: Выделить всё
headerData() - используется для форматирования необработанных значений и применения некоторых стилей. Это моя реализация data():
Код: Выделить всё
data()Метод
Код: Выделить всё
QVariant EquipmentModel::data(const QModelIndex &item, int role) const {
// shortcuts
QVariant value = QSqlQueryModel::data(item, role);
int column = item.column();
// stash raw value for column 2
if (role == Qt::UserRole) {
if (column == 2)
return QSqlQueryModel::data(item, Qt::DisplayRole);
}
// data to be displayed
if (role == Qt::DisplayRole) {
// name
if (column == 1)
return value;
// type
if (column == 2) {
if (value.toString() == APP_TYPE1)
return QString(APP_TYPE1_TXT);
if (value.toString() == APP_TYPE2)
return QString(APP_TYPE2_TXT);
if (value.toString() == APP_TYPE)
return QString(APP_TYPE3_TXT);
}
// verification dates
if ((column == 3) || (column == 4)) {
if (value.isNull())
return QVariant(QMetaType::fromType());
else
return QDateTime::fromString(value.toString(), Qt::ISODate).toString("dd.MM.yyyy");
}
}
// text alignment in a cell
if (role == Qt::TextAlignmentRole) {
// default alignment
int alignment = Qt::AlignVCenter;
// type, verification date, verification valid to
if ((column == 2) || (column == 3) || (column == 4))
alignment |= Qt::AlignCenter;
// name
if (column == 1)
alignment |= Qt::AlignLeft;
return alignment;
}
// background colors
if (role == Qt::BackgroundRole) {
// verification date
if (
(column == 3) &&
(item.siblingAtColumn(2).data(Qt::UserRole).toString() == APP_TYPE1) &&
item.data(Qt::DisplayRole).isNull())
return QBrush(QColor("red"), Qt::SolidPattern);
// verification upto date
if (
(column == 4) &&
(item.siblingAtColumn(2).data(Qt::UserRole).toString() == APP_TYPE1)) {
// time has out or empty value (no info about verifications)
if (item.data(Qt::DisplayRole).isNull() || (item.siblingAtColumn(5).data(Qt::DisplayRole).toInt() setQuery(basic_query.arg("1 = 1"));
Код: Выделить всё
QSqlQuery q;
q.prepare(basic_query.arg("e.name LIKE :search OR s.name LIKE :search OR s.description LIKE :search OR s.sn LIKE :search"));
q.bindValue(":search", QString("%%1%").arg(SearchStringFld->text()));
q.exec();
model->setQuery(std::move(q));
Чтобы проверить, не является ли это проблемой с подготовленным запросом, я заменил назначение запроса на это:
Код: Выделить всё
model->setQuery(basic_query.arg("e.name LIKE '%%1%' OR s.name LIKE '%%1%' OR s.description LIKE '%%1%' OR s.sn LIKE '%%1%'").arg(SearchStringFld->text()));


Как вы можете видеть, количество строк в запросе одинаковое, столбец 1 заполняется правильно, и цвет фона также применяется, однако столбцы 3 и 4 не заполняются из-за недопустимого QDate в случае подготовленного запроса. Это похоже на ошибку в Qt, однако есть вероятность, что я делаю что-то ужасно неправильно. Я нашел тему на форуме Qt, в которой дается тот же совет: не выделяйте память в куче, используйте стек, а затем переходите к setQuery(). В этом случае я бы хотел использовать подготовленный запрос, потому что я имею дело с пользовательским вводом и хочу избежать SQL-инъекций во время моих запросов к БД.
Итак, подведем итог: я делаю что-то не так? Как правильно использовать подготовленные запросы в Qt 6 при назначении их моделям?
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ
Я обнаружил, что проблема каким-то образом связана с типами данных, используемыми в базе данных (в моем случае MariaDB). Чтобы проверить это, я изменил тип данных для столбцов 3 и 4 с DATE на INT и отредактировал SQL-запрос, чтобы использовать прямую разницу вместо DATEDIFF - и все работает отлично! Похоже, что QSqlQueryModel каким-то образом делает недействительными значения для этих столбцов при последовательных запросах, поэтому вместо этого возвращается QDate(Invalid). Это не было проблемой, по крайней мере, в Qt 5.12. Возможно, некоторая обработка даты и времени была изменена во время цикла разработки Qt 6...
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ 2
Существует MRE:
- CMakeLists.txt
- main.cpp
- содержит только учетные данные БД, я не буду публиковать его здесь.
Код: Выделить всё
main.h - Схема базы данных

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ 3
Если я изменю свой базовый оператор SQL-запроса (первая его строка) с:
Код: Выделить всё
"SELECT DISTINCT e.id, e.name, e.type, v.ts, v.upto, v.d_left "Код: Выделить всё
"SELECT DISTINCT e.id, e.name, e.type, DATE_FORMAT(v.ts, '%d.%m.%Y'), DATE_FORMAT(v.upto, '%d.%m.%Y'), v.d_left "
Итак, похоже, что QSqlQueryModel каким-то образом плохо себя ведет в связи с QTableView, когда некоторые столбцы имеют тип QDate
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ 4
Существует пример набора данных с анонимизированными строками
Подробнее здесь: https://stackoverflow.com/questions/798 ... s-prepared
Мобильная версия