Может показаться, что делать наследника от QSqlRecord нет никакой необходимости.
Но на этапе, когда мы создали форму для редактирования строки таблицы, мы передали ей в качестве исходных данных QSqlRecord, открываемой строки таблицы, нам надо иметь id внешних связей.
Это логично. И вот тогда стало понятно, что надо внутри QSqlRecord иметь информацию по значениям id полей внешних связей. Все как в классе QpSqlTableModel.
QSqlRecord это самостоятельный класс, без родителя. По сути это удобная обертка над полями одной строки.
Заполнение информации в QSqlRecord происходит в классе модели данных QSqlQueryModel, а именно в функции record.
Получив QSqlRecord по номеру строки из модели данных его можно копировать, сравнивать с другим QSqlRecord, присваивать, то есть удобно манипулировать данными строки в целом.
То есть это все про удобство манипулирования строками.
После того как у нас произошло развитие класса модели данных QSqlTableModel в QpSqlTabelModel показалось, что возникла необходимость форкнуть и класс QSqlRecord, чтобы исполЬзовать преимущества нового развития.
QSqlRecord самодостаточен. Он содержит все поля запроса к базе данных, которые формирует selectStatement функция. А selectStatement принадлежит модели данных.
Итак представляем наследника QSqlRecord: QpSqlRecord .
В QpSqlRecord нам надо содержать информацию о полях с внешней связью. Точнее какое дополнительное поле является id внешней связи для заданного номера поля (если конечно такое есть).
По сути QpSqlRecord добавляет карту QHash соответствия оригинальных relation полей и полей, где лежат их id связей.
На самом деле добавить карту соответствия полей можно в методе record модели данных, в котором единственно и происходит создание об'екта QSqlRecord.
Вот функция record класса QSqlQueryModel.
QSqlRecord QSqlQueryModel::record(int row) const
{
Q_D(const QSqlQueryModel);
if (row < 0)
return d->rec;
QSqlRecord rec = d->rec; // вызывается конструктор копирования, d->rec пустой (это только набор полей)
for (int i = 0; i < rec.count(); i)
rec.setValue(i, data(createIndex(row, i), Qt::EditRole));
return rec;
}
Вопрос: как лучше поступить?
Можно полностью переопределить функцию record в нашем классе наследнике (QpSqlTableModel). И в QpSqlTableModel будет своя record, а QSqlQueryModel будет своя функция record .
Можно попытаться оставить QSqlQueryModel::record и как-то выкрутится через каст.Например подойдет вариант reinterpretet_cast:
QpSqlRecord pblRec = reinterpret_cast(QSqlQueryModel::record(row));
Далее надо после reinterpret_cast все данные экземпляра QpSqlRecord не забыть проинициализировать.
И еще есть третий вариант, как нам кажется более логичный и правильный, но строчек кода будет побольше. Во первый надо переопределить конструктор копирования с не тривиальным передаваемым параметром (ссылка на объект копирования предка). А именно речь об этом
QpSqlRecord(const QSqlRecord& other);
class Q_SQL_EXPORT QpSqlRecord: public QSqlRecord
{
public:
QpSqlRecord();
QpSqlRecord(const QpSqlRecord& other); // конструктор копирования стандартный QpSqlRecord(const QSqlRecord& other); // конструктор копирования не стандартный (для функции record)
QpSqlRecord& operator=(const QpSqlRecord& other);
Именно в этом случае мы сможет выполнить строку кода:
QpSqlRecord pblRec(QSqlQueryModel::record(row));
И все будет работать ОК. То есть получается, что мы передаем параметром в конструктор копирования ссылку на объект родителя, что нам и нужно.(см.конструкторы, деструкторы)
Как можно еще решить данную проблему - думаю уже достаточно вариантов и не будем до поры до времени об этом беспокоится.
Вообще-то напрашивается вариант конструктора перемещения, но это стандарт С11, в Qt 4.8.1 вроде бы ещё не используемый. Надо будет попробовать.