развитие QSqlRecord

фотка 1

Может показаться, что делать наследника от 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 вроде бы ещё не используемый. Надо будет попробовать.