Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsqlrelationaltablemodel.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include "qhash.h"
8#include "qstringlist.h"
9#include "qsqldatabase.h"
10#include "qsqldriver.h"
11#include "qsqlerror.h"
12#include "qsqlfield.h"
13#include "qsqlindex.h"
14#include "qsqlquery.h"
15#include "qsqlrecord.h"
16
18
19#include "qdebug.h"
20
22
23using namespace Qt::StringLiterals;
24
26{
27public:
28 inline const static QString relTablePrefix(int i) { return QString::number(i).prepend("relTblAl_"_L1); }
29};
30
32
33/*!
34 \class QSqlRelation
35 \inmodule QtSql
36 \brief The QSqlRelation class stores information about an SQL foreign key.
37
38 QSqlRelation is a helper class for QSqlRelationalTableModel. See
39 QSqlRelationalTableModel::setRelation() and
40 QSqlRelationalTableModel::relation() for details.
41
42 \sa QSqlRelationalTableModel, QSqlRelationalDelegate,
43 {Relational Table Model Example}
44*/
45
46/*!
47 \fn QSqlRelation::QSqlRelation()
48
49 Constructs an invalid QSqlRelation object.
50
51 For such an object, the tableName(), indexColumn(), and
52 displayColumn() functions return an empty string.
53
54 \sa isValid()
55*/
56
57/*!
58 \fn QSqlRelation::QSqlRelation(const QString &tableName, const QString &indexColumn,
59 const QString &displayColumn)
60
61 Constructs a QSqlRelation object, where \a tableName is the SQL
62 table name to which a foreign key refers, \a indexColumn is the
63 foreign key, and \a displayColumn is the field that should be
64 presented to the user.
65
66 \sa tableName(), indexColumn(), displayColumn()
67*/
68
69/*!
70 \fn void QSqlRelation::swap(QSqlRelation &other)
71 \memberswap{relation}
72 */
73
74/*!
75 \fn QString QSqlRelation::tableName() const
76
77 Returns the name of the table to which a foreign key refers.
78*/
79
80/*!
81 \fn QString QSqlRelation::indexColumn() const
82
83 Returns the index column from table tableName() to which a
84 foreign key refers.
85*/
86
87/*!
88 \fn QString QSqlRelation::displayColumn() const
89
90 Returns the column from table tableName() that should be
91 presented to the user instead of a foreign key.
92*/
93
94/*!
95 \fn bool QSqlRelation::isValid() const
96
97 Returns \c true if the QSqlRelation object is valid; otherwise
98 returns \c false.
99*/
100
102
104{
105 public:
106 Q_DISABLE_COPY(QRelation) // QRelatedTableModel stores a pointer to this class
107 QRelation() = default;
108 void init(QSqlRelationalTableModel *parent, const QSqlRelation &relation, int column);
109
111
115
116 void clear();
117 bool isValid() const;
118
121 QHash<QString, QVariant> dictionary;//maps keys to display values
122
123 private:
124 QSqlRelationalTableModel *m_parent = nullptr;
125 int col = -1;
126 bool m_dictInitialized = false;
127};
128
130{
131public:
132 QRelatedTableModel(QRelation *rel, QObject *parent, const QSqlDatabase &db);
134private:
135 bool firstSelect;
136 QRelation *relation;
137};
138/*
139 A QRelation must be initialized before it is considered valid.
140 Note: population of the model and dictionary are kept separate
141 from initialization, and are populated on an as needed basis.
142*/
143void QRelation::init(QSqlRelationalTableModel *parent, const QSqlRelation &relation, int column)
144{
145 Q_ASSERT(parent != nullptr);
146 m_parent = parent;
147 rel = relation;
148 col = column;
149}
150
152{
153 if (!isValid())
154 return;
155 Q_ASSERT(m_parent != nullptr);
156
157 if (!model) {
158 model = new QRelatedTableModel(this, m_parent, m_parent->database());
159 model->setTable(rel.tableName());
161 QObject::connect(model, &QAbstractItemModel::dataChanged, model, [&](const QModelIndex &tl, const QModelIndex &br)
162 {
163 if (tl.column() >= col && br.column() <= col)
164 clearDictionary();
165 });
166 QObject::connect(model, &QAbstractItemModel::rowsRemoved, model, [&]()
167 {
168 clearDictionary();
169 });
170 QObject::connect(model, &QAbstractItemModel::rowsInserted, model, [&]()
171 {
172 clearDictionary();
173 });
174 }
175}
176
178{
179 return m_dictInitialized;
180}
181
183{
184 if (!isValid())
185 return;
186
187 if (model == nullptr)
189
190 QSqlRecord record;
191 QString indexColumn;
192 QString displayColumn;
193 for (int i=0; i < model->rowCount(); ++i) {
194 record = model->record(i);
195
196 indexColumn = rel.indexColumn();
197 if (m_parent->database().driver()->isIdentifierEscaped(indexColumn, QSqlDriver::FieldName))
198 indexColumn = m_parent->database().driver()->stripDelimiters(indexColumn, QSqlDriver::FieldName);
199
200 displayColumn = rel.displayColumn();
201 if (m_parent->database().driver()->isIdentifierEscaped(displayColumn, QSqlDriver::FieldName))
202 displayColumn = m_parent->database().driver()->stripDelimiters(displayColumn, QSqlDriver::FieldName);
203
204 dictionary[record.field(indexColumn).value().toString()] =
205 record.field(displayColumn).value();
206 }
207 m_dictInitialized = true;
208}
209
211{
212 dictionary.clear();
213 m_dictInitialized = false;
214}
215
217{
218 delete model;
219 model = nullptr;
221}
222
223bool QRelation::isValid() const
224{
225 return (rel.isValid() && m_parent != nullptr);
226}
227
228
229
230QRelatedTableModel::QRelatedTableModel(QRelation *rel, QObject *parent, const QSqlDatabase &db) :
231 QSqlTableModel(parent, db), firstSelect(true), relation(rel)
232{
233}
234
236{
237 if (firstSelect) {
238 firstSelect = false;
239 return QSqlTableModel::select();
240 }
241 relation->clearDictionary();
242 bool res = QSqlTableModel::select();
243 if (res)
245 return res;
246}
247
248
250{
251 Q_DECLARE_PUBLIC(QSqlRelationalTableModel)
252public:
258
259 int nameToIndex(const QString &name) const override;
261 QSqlRecord baseRec; // the record without relations
265
266 void translateFieldNames(QSqlRecord &values) const;
268};
269
271{
272 for (auto &rel : relations)
273 rel->clear();
274}
275
277{
278 QSqlTableModelPrivate::revertCachedRow(row);
279}
280
281int QSqlRelationalTableModelPrivate::nameToIndex(const QString &name) const
282{
283 const QString fieldname = strippedFieldName(name);
284 int idx = baseRec.indexOf(fieldname);
285 if (idx == -1) {
286 // If the name is an alias we can find it here.
287 idx = QSqlTableModelPrivate::nameToIndex(name);
288 }
289 return idx;
290}
291
293{
294 for (auto &rel : relations)
295 rel->clearDictionary();
296
297 QSqlTableModelPrivate::clearCache();
298}
299
300/*!
301 \class QSqlRelationalTableModel
302 \brief The QSqlRelationalTableModel class provides an editable
303 data model for a single database table, with foreign key support.
304
305 \ingroup database
306 \inmodule QtSql
307
308 QSqlRelationalTableModel acts like QSqlTableModel, but allows
309 columns to be set as foreign keys into other database tables.
310
311 \table
312 \row \li \inlineimage noforeignkeys.png
313 \li \inlineimage foreignkeys.png
314 \endtable
315
316 The screenshot on the left shows a plain QSqlTableModel in a
317 QTableView. Foreign keys (\c city and \c country) aren't resolved
318 to human-readable values. The screenshot on the right shows a
319 QSqlRelationalTableModel, with foreign keys resolved into
320 human-readable text strings.
321
322 The following code snippet shows how the QSqlRelationalTableModel
323 was set up:
324
325 \snippet relationaltablemodel/relationaltablemodel.cpp 0
326 \codeline
327 \snippet relationaltablemodel/relationaltablemodel.cpp 1
328 \snippet relationaltablemodel/relationaltablemodel.cpp 2
329
330 The setRelation() function calls establish a relationship between
331 two tables. The first call specifies that column 2 in table \c
332 employee is a foreign key that maps with field \c id of table \c
333 city, and that the view should present the \c{city}'s \c name
334 field to the user. The second call does something similar with
335 column 3.
336
337 If you use a read-write QSqlRelationalTableModel, you probably
338 want to use QSqlRelationalDelegate on the view. Unlike the default
339 delegate, QSqlRelationalDelegate provides a combobox for fields
340 that are foreign keys into other tables. To use the class, simply
341 call QAbstractItemView::setItemDelegate() on the view with an
342 instance of QSqlRelationalDelegate:
343
344 \snippet relationaltablemodel/relationaltablemodel.cpp 4
345
346 The \l{relationaltablemodel} example illustrates how to use
347 QSqlRelationalTableModel in conjunction with
348 QSqlRelationalDelegate to provide tables with foreign key
349 support.
350
351 \image relationaltable.png {The user is able to edit a foreign key in a relational table}
352
353 Notes:
354
355 \list
356 \li The table must have a primary key declared.
357 \li The table's primary key may not contain a relation to
358 another table.
359 \li If a relational table contains keys that refer to non-existent
360 rows in the referenced table, the rows containing the invalid
361 keys will not be exposed through the model. The user or the
362 database is responsible for keeping referential integrity.
363 \li If a relation's display column name is also used as a column
364 name in the relational table, or if it is used as display column
365 name in more than one relation it will be aliased. The alias is
366 the relation's table name, display column name and a unique id
367 joined by an underscore (e.g. tablename_columnname_id).
368 QSqlRecord::fieldName() will return the aliased column name.
369 All occurrences of the duplicate display column name are aliased when
370 duplication is detected, but no aliasing is done to the column
371 names in the main table. The aliasing doesn't affect
372 QSqlRelation, so QSqlRelation::displayColumn() will return the
373 original display column name.
374 \li The reference table name is aliased. The alias is the word "relTblAl"
375 and the relationed column index joined by an underscore
376 (e.g. relTblAl_2). The alias can be used to filter the table
377 (For example, setFilter("relTblAl_2='Oslo' OR
378 relTblAl_3='USA'")).
379 \li When using setData() the role should always be Qt::EditRole,
380 and when using data() the role should always be Qt::DisplayRole.
381 \endlist
382
383 \sa QSqlRelation, QSqlRelationalDelegate,
384 {Relational Table Model Example}
385*/
386
387
388/*!
389 Creates an empty QSqlRelationalTableModel and sets the parent to \a parent
390 and the database connection to \a db. If \a db is not valid, the
391 default database connection will be used.
392*/
393QSqlRelationalTableModel::QSqlRelationalTableModel(QObject *parent, const QSqlDatabase &db)
394 : QSqlTableModel(*new QSqlRelationalTableModelPrivate, parent, db)
395{
396}
397
398/*!
399 Destroys the object and frees any allocated resources.
400*/
401QSqlRelationalTableModel::~QSqlRelationalTableModel()
402{
403}
404
405/*!
406 \reimp
407*/
408QVariant QSqlRelationalTableModel::data(const QModelIndex &index, int role) const
409{
410 Q_D(const QSqlRelationalTableModel);
411
412 if (role == Qt::DisplayRole && index.column() >= 0 && index.column() < d->relations.size() &&
413 d->relations.at(index.column())->isValid()) {
414 auto relation = d->relations.at(index.column());
415 if (!relation->isDictionaryInitialized())
416 relation->populateDictionary();
417
418 //only perform a dictionary lookup for the display value
419 //when the value at index has been changed or added.
420 //At an unmodified index, the underlying model will
421 //already have the correct display value.
422 if (d->strategy != OnFieldChange) {
423 const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
424 if (row.op() != QSqlTableModelPrivate::None && row.rec().isGenerated(index.column())) {
425 if (d->strategy == OnManualSubmit || row.op() != QSqlTableModelPrivate::Delete) {
426 QVariant v = row.rec().value(index.column());
427 if (v.isValid())
428 return relation->dictionary[v.toString()];
429 }
430 }
431 }
432 }
433 return QSqlTableModel::data(index, role);
434}
435
436/*!
437 Sets the data for the \a role in the item with the specified \a
438 index to the \a value given. Depending on the edit strategy, the
439 value might be applied to the database at once, or it may be
440 cached in the model.
441
442 Returns \c true if the value could be set, or false on error (for
443 example, if \a index is out of bounds).
444
445 For relational columns, \a value must be the index, not the
446 display value. If an index is given, it must also exist in the
447 referenced table, otherwise the function returns \c false.
448 If a QVariant() is passed instead of an index, the index is cleared.
449
450 \sa editStrategy(), data(), submit(), revertRow()
451*/
452bool QSqlRelationalTableModel::setData(const QModelIndex &index, const QVariant &value,
453 int role)
454{
455 Q_D(QSqlRelationalTableModel);
456 if ( role == Qt::EditRole && index.column() > 0 && index.column() < d->relations.size()
457 && d->relations.at(index.column())->isValid()) {
458 auto relation = d->relations.at(index.column());
459 if (!relation->isDictionaryInitialized())
460 relation->populateDictionary();
461 if (value.isValid() && !relation->dictionary.contains(value.toString()))
462 return false;
463 }
464 return QSqlTableModel::setData(index, value, role);
465}
466
467/*!
468 Lets the specified \a column be a foreign index specified by \a relation.
469
470 Example:
471
472 \snippet relationaltablemodel/relationaltablemodel.cpp 0
473 \codeline
474 \snippet relationaltablemodel/relationaltablemodel.cpp 1
475
476 The setRelation() call specifies that column 2 in table \c
477 employee is a foreign key that maps with field \c id of table \c
478 city, and that the view should present the \c{city}'s \c name
479 field to the user.
480
481 Note: The table's primary key may not contain a relation to another table.
482
483 \sa relation()
484*/
485void QSqlRelationalTableModel::setRelation(int column, const QSqlRelation &relation)
486{
487 Q_D(QSqlRelationalTableModel);
488 if (column < 0)
489 return;
490 if (d->relations.size() <= column) {
491 const auto oldSize = d->relations.size();
492 d->relations.resize(column + 1);
493 for (auto i = oldSize; i < d->relations.size(); ++i)
494 d->relations[i] = QSharedPointer<QRelation>::create();
495 }
496 d->relations.at(column)->init(this, relation, column);
497}
498
499/*!
500 Returns the relation for the column \a column, or an invalid
501 relation if no relation is set.
502
503 \sa setRelation(), QSqlRelation::isValid()
504*/
505QSqlRelation QSqlRelationalTableModel::relation(int column) const
506{
507 Q_D(const QSqlRelationalTableModel);
508 return d->relations.value(column) ? d->relations.at(column)->rel : QSqlRelation();
509}
510
511QString QSqlRelationalTableModelPrivate::fullyQualifiedFieldName(const QString &tableName,
512 const QString &fieldName) const
513{
514 QString ret;
515 ret.reserve(tableName.size() + fieldName.size() + 1);
516 ret.append(tableName).append(u'.').append(fieldName);
517
518 return ret;
519}
520
521/*!
522 \reimp
523*/
524QString QSqlRelationalTableModel::selectStatement() const
525{
526 Q_D(const QSqlRelationalTableModel);
527
528 if (tableName().isEmpty())
529 return QString();
530 if (d->relations.isEmpty())
531 return QSqlTableModel::selectStatement();
532
533 // Count how many times each field name occurs in the record
534 QHash<QString, int> fieldNames;
535 QStringList fieldList;
536 for (int i = 0; i < d->baseRec.count(); ++i) {
537 QSqlRelation relation = d->relations.value(i) ? d->relations.at(i)->rel : QSqlRelation();
538 QString name;
539 if (relation.isValid()) {
540 // Count the display column name, not the original foreign key
541 name = relation.displayColumn();
542 if (d->db.driver()->isIdentifierEscaped(name, QSqlDriver::FieldName))
543 name = d->db.driver()->stripDelimiters(name, QSqlDriver::FieldName);
544
545 const QSqlRecord rec = database().record(relation.tableName());
546 for (int i = 0; i < rec.count(); ++i) {
547 if (name.compare(rec.fieldName(i), Qt::CaseInsensitive) == 0) {
548 name = rec.fieldName(i);
549 break;
550 }
551 }
552 }
553 else {
554 name = d->baseRec.fieldName(i);
555 }
556 fieldNames[name] = fieldNames.value(name, 0) + 1;
557 fieldList.append(name);
558 }
559
560 QString fList;
561 QString conditions;
562 QString from = SqlrTm::from(tableName());
563 for (int i = 0; i < d->baseRec.count(); ++i) {
564 QSqlRelation relation = d->relations.value(i) ? d->relations.at(i)->rel : QSqlRelation();
565 const QString tableField = d->fullyQualifiedFieldName(tableName(), d->db.driver()->escapeIdentifier(d->baseRec.fieldName(i), QSqlDriver::FieldName));
566 if (relation.isValid()) {
567 const QString relTableAlias = SqlrTm::relTablePrefix(i);
568 QString displayTableField = d->fullyQualifiedFieldName(relTableAlias, relation.displayColumn());
569
570 // Duplicate field names must be aliased
571 if (fieldNames.value(fieldList[i]) > 1) {
572 QString relTableName = relation.tableName().section(QChar::fromLatin1('.'), -1, -1);
573 if (d->db.driver()->isIdentifierEscaped(relTableName, QSqlDriver::TableName))
574 relTableName = d->db.driver()->stripDelimiters(relTableName, QSqlDriver::TableName);
575 QString displayColumn = relation.displayColumn();
576 if (d->db.driver()->isIdentifierEscaped(displayColumn, QSqlDriver::FieldName))
577 displayColumn = d->db.driver()->stripDelimiters(displayColumn, QSqlDriver::FieldName);
578 QString alias = QString::fromLatin1("%1_%2_%3")
579 .arg(relTableName, displayColumn, QString::number(fieldNames.value(fieldList[i])));
580 alias.truncate(d->db.driver()->maximumIdentifierLength(QSqlDriver::FieldName));
581 alias = d->db.driver()->escapeIdentifier(alias, QSqlDriver::FieldName);
582 displayTableField = SqlrTm::as(displayTableField, alias);
583 --fieldNames[fieldList[i]];
584 }
585
586 fList = SqlrTm::comma(fList, displayTableField);
587
588 // Join related table
589 const QString tblexpr = SqlrTm::concat(relation.tableName(), relTableAlias);
590 const QString relTableField = d->fullyQualifiedFieldName(relTableAlias, relation.indexColumn());
591 const QString cond = SqlrTm::eq(tableField, relTableField);
592 if (d->joinMode == QSqlRelationalTableModel::InnerJoin) {
593 // FIXME: InnerJoin code is known to be broken.
594 // Use LeftJoin mode if you want correct behavior.
595 from = SqlrTm::comma(from, tblexpr);
596 conditions = SqlrTm::et(conditions, cond);
597 } else {
598 from = SqlrTm::concat(from, SqlrTm::leftJoin(tblexpr));
599 from = SqlrTm::concat(from, SqlrTm::on(cond));
600 }
601 } else {
602 fList = SqlrTm::comma(fList, tableField);
603 }
604 }
605
606 if (fList.isEmpty())
607 return QString();
608
609 const QString stmt = SqlrTm::concat(SqlrTm::select(fList), from);
610 const QString where = SqlrTm::where(SqlrTm::et(SqlrTm::paren(conditions), SqlrTm::paren(filter())));
611 return SqlrTm::concat(SqlrTm::concat(stmt, where), orderByClause());
612}
613
614/*!
615 Returns a QSqlTableModel object for accessing the table for which
616 \a column is a foreign key, or \nullptr if there is no relation for
617 the given \a column.
618
619 The returned object is owned by the QSqlRelationalTableModel.
620
621 \sa setRelation(), relation()
622*/
623QSqlTableModel *QSqlRelationalTableModel::relationModel(int column) const
624{
625 Q_D(const QSqlRelationalTableModel);
626 if (column < 0 || column >= d->relations.size())
627 return nullptr;
628
629 auto relation = d->relations.at(column);
630 if (!relation || !relation->isValid())
631 return nullptr;
632
633 if (!relation->model)
634 relation->populateModel();
635 return relation->model;
636}
637
638/*!
639 \reimp
640*/
641void QSqlRelationalTableModel::revertRow(int row)
642{
643 QSqlTableModel::revertRow(row);
644}
645
646/*!
647 \reimp
648*/
649void QSqlRelationalTableModel::clear()
650{
651 Q_D(QSqlRelationalTableModel);
652 beginResetModel();
653 d->clearChanges();
654 d->relations.clear();
655 QSqlTableModel::clear();
656 endResetModel();
657}
658
659
660/*! \enum QSqlRelationalTableModel::JoinMode
661
662 \value InnerJoin - Inner join mode, return rows when there is at least one match in both tables.
663 \value LeftJoin - Left join mode, returns all rows from the left table (table_name1), even if there are no matches in the right table (table_name2).
664
665 \sa QSqlRelationalTableModel::setJoinMode()
666*/
667
668/*!
669 Sets the SQL \a joinMode to show or hide rows with NULL foreign keys.
670 In InnerJoin mode (the default) these rows will not be shown: use the
671 LeftJoin mode if you want to show them.
672
673 \sa QSqlRelationalTableModel::JoinMode
674*/
675void QSqlRelationalTableModel::setJoinMode( QSqlRelationalTableModel::JoinMode joinMode )
676{
677 Q_D(QSqlRelationalTableModel);
678 d->joinMode = joinMode;
679}
680/*!
681 \reimp
682*/
683bool QSqlRelationalTableModel::select()
684{
685 return QSqlTableModel::select();
686}
687
688/*!
689 \reimp
690*/
691void QSqlRelationalTableModel::setTable(const QString &table)
692{
693 Q_D(QSqlRelationalTableModel);
694
695 // memorize the table before applying the relations
696 d->baseRec = d->db.record(table);
697
698 QSqlTableModel::setTable(table);
699}
700
701/*! \internal
702 */
704{
705 for (int i = 0; i < values.count(); ++i) {
706 if (relations.value(i) && relations.at(i)->isValid()) {
707 QVariant v = values.value(i);
708 bool gen = values.isGenerated(i);
709 values.replace(i, baseRec.field(i));
710 values.setValue(i, v);
711 values.setGenerated(i, gen);
712 }
713 }
714}
715
716/*!
717 \reimp
718*/
719bool QSqlRelationalTableModel::updateRowInTable(int row, const QSqlRecord &values)
720{
721 Q_D(QSqlRelationalTableModel);
722
723 QSqlRecord rec = values;
724 d->translateFieldNames(rec);
725
726 return QSqlTableModel::updateRowInTable(row, rec);
727}
728
729/*!
730 \reimp
731*/
732bool QSqlRelationalTableModel::insertRowIntoTable(const QSqlRecord &values)
733{
734 Q_D(QSqlRelationalTableModel);
735
736 QSqlRecord rec = values;
737 d->translateFieldNames(rec);
738
739 return QSqlTableModel::insertRowIntoTable(rec);
740}
741
742/*!
743 \reimp
744*/
745QString QSqlRelationalTableModel::orderByClause() const
746{
747 Q_D(const QSqlRelationalTableModel);
748
749 const QSqlRelation rel = d->relations.value(d->sortColumn) ? d->relations.at(d->sortColumn)->rel : QSqlRelation();
750 if (!rel.isValid())
751 return QSqlTableModel::orderByClause();
752
753 QString f = d->fullyQualifiedFieldName(SqlrTm::relTablePrefix(d->sortColumn), rel.displayColumn());
754 f = d->sortOrder == Qt::AscendingOrder ? SqlrTm::asc(f) : SqlrTm::desc(f);
755 return SqlrTm::orderBy(f);
756}
757
758/*!
759 \reimp
760*/
761bool QSqlRelationalTableModel::removeColumns(int column, int count, const QModelIndex &parent)
762{
763 Q_D(QSqlRelationalTableModel);
764
765 if (parent.isValid() || column < 0 || column + count > d->rec.count())
766 return false;
767
768 for (int i = 0; i < count; ++i) {
769 d->baseRec.remove(column);
770 if (d->relations.size() > column)
771 d->relations.remove(column);
772 }
773 return QSqlTableModel::removeColumns(column, count, parent);
774}
775
776QT_END_NAMESPACE
777
778#include "moc_qsqlrelationaltablemodel.cpp"
QRelatedTableModel(QRelation *rel, QObject *parent, const QSqlDatabase &db)
bool select() override
Populates the model with data from the table that was set via setTable(), using the specified filter ...
QList< QSharedPointer< QRelation > > relations
int nameToIndex(const QString &name) const override
void translateFieldNames(QSqlRecord &values) const
static const QString relTablePrefix(int i)
QSqlRelationalTableModelSql SqlrTm
QRelatedTableModel * model
bool isDictionaryInitialized() const
QHash< QString, QVariant > dictionary
void init(QSqlRelationalTableModel *parent, const QSqlRelation &relation, int column)