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 {Table showing city and country as numeric foreign key values}
314 \li \inlineimage foreignkeys.png
315 {Table showing city and country resolved to text strings}
316 \endtable
317
318 The screenshot on the left shows a plain QSqlTableModel in a
319 QTableView. Foreign keys (\c city and \c country) aren't resolved
320 to human-readable values. The screenshot on the right shows a
321 QSqlRelationalTableModel, with foreign keys resolved into
322 human-readable text strings.
323
324 The following code snippet shows how the QSqlRelationalTableModel
325 was set up:
326
327 \snippet relationaltablemodel/relationaltablemodel.cpp 0
328 \codeline
329 \snippet relationaltablemodel/relationaltablemodel.cpp 1
330 \snippet relationaltablemodel/relationaltablemodel.cpp 2
331
332 The setRelation() function calls establish a relationship between
333 two tables. The first call specifies that column 2 in table \c
334 employee is a foreign key that maps with field \c id of table \c
335 city, and that the view should present the \c{city}'s \c name
336 field to the user. The second call does something similar with
337 column 3.
338
339 If you use a read-write QSqlRelationalTableModel, you probably
340 want to use QSqlRelationalDelegate on the view. Unlike the default
341 delegate, QSqlRelationalDelegate provides a combobox for fields
342 that are foreign keys into other tables. To use the class, simply
343 call QAbstractItemView::setItemDelegate() on the view with an
344 instance of QSqlRelationalDelegate:
345
346 \snippet relationaltablemodel/relationaltablemodel.cpp 4
347
348 The \l{relationaltablemodel} example illustrates how to use
349 QSqlRelationalTableModel in conjunction with
350 QSqlRelationalDelegate to provide tables with foreign key
351 support.
352
353 \image relationaltable.png {The user is able to edit a foreign key in a relational table}
354
355 Notes:
356
357 \list
358 \li The table must have a primary key declared.
359 \li The table's primary key may not contain a relation to
360 another table.
361 \li If a relational table contains keys that refer to non-existent
362 rows in the referenced table, the rows containing the invalid
363 keys will not be exposed through the model. The user or the
364 database is responsible for keeping referential integrity.
365 \li If a relation's display column name is also used as a column
366 name in the relational table, or if it is used as display column
367 name in more than one relation it will be aliased. The alias is
368 the relation's table name, display column name and a unique id
369 joined by an underscore (e.g. tablename_columnname_id).
370 QSqlRecord::fieldName() will return the aliased column name.
371 All occurrences of the duplicate display column name are aliased when
372 duplication is detected, but no aliasing is done to the column
373 names in the main table. The aliasing doesn't affect
374 QSqlRelation, so QSqlRelation::displayColumn() will return the
375 original display column name.
376 \li The reference table name is aliased. The alias is the word "relTblAl"
377 and the relationed column index joined by an underscore
378 (e.g. relTblAl_2). The alias can be used to filter the table
379 (For example, setFilter("relTblAl_2='Oslo' OR
380 relTblAl_3='USA'")).
381 \li When using setData() the role should always be Qt::EditRole,
382 and when using data() the role should always be Qt::DisplayRole.
383 \endlist
384
385 \sa QSqlRelation, QSqlRelationalDelegate,
386 {Relational Table Model Example}
387*/
388
389
390/*!
391 Creates an empty QSqlRelationalTableModel and sets the parent to \a parent
392 and the database connection to \a db. If \a db is not valid, the
393 default database connection will be used.
394*/
395QSqlRelationalTableModel::QSqlRelationalTableModel(QObject *parent, const QSqlDatabase &db)
396 : QSqlTableModel(*new QSqlRelationalTableModelPrivate, parent, db)
397{
398}
399
400/*!
401 Destroys the object and frees any allocated resources.
402*/
403QSqlRelationalTableModel::~QSqlRelationalTableModel()
404{
405}
406
407/*!
408 \reimp
409*/
410QVariant QSqlRelationalTableModel::data(const QModelIndex &index, int role) const
411{
412 Q_D(const QSqlRelationalTableModel);
413
414 if (role == Qt::DisplayRole && index.column() >= 0 && index.column() < d->relations.size() &&
415 d->relations.at(index.column())->isValid()) {
416 auto relation = d->relations.at(index.column());
417 if (!relation->isDictionaryInitialized())
418 relation->populateDictionary();
419
420 //only perform a dictionary lookup for the display value
421 //when the value at index has been changed or added.
422 //At an unmodified index, the underlying model will
423 //already have the correct display value.
424 if (d->strategy != OnFieldChange) {
425 const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
426 if (row.op() != QSqlTableModelPrivate::None && row.rec().isGenerated(index.column())) {
427 if (d->strategy == OnManualSubmit || row.op() != QSqlTableModelPrivate::Delete) {
428 QVariant v = row.rec().value(index.column());
429 if (v.isValid())
430 return relation->dictionary[v.toString()];
431 }
432 }
433 }
434 }
435 return QSqlTableModel::data(index, role);
436}
437
438/*!
439 Sets the data for the \a role in the item with the specified \a
440 index to the \a value given. Depending on the edit strategy, the
441 value might be applied to the database at once, or it may be
442 cached in the model.
443
444 Returns \c true if the value could be set, or false on error (for
445 example, if \a index is out of bounds).
446
447 For relational columns, \a value must be the index, not the
448 display value. If an index is given, it must also exist in the
449 referenced table, otherwise the function returns \c false.
450 If a QVariant() is passed instead of an index, the index is cleared.
451
452 \sa editStrategy(), data(), submit(), revertRow()
453*/
454bool QSqlRelationalTableModel::setData(const QModelIndex &index, const QVariant &value,
455 int role)
456{
457 Q_D(QSqlRelationalTableModel);
458 if ( role == Qt::EditRole && index.column() > 0 && index.column() < d->relations.size()
459 && d->relations.at(index.column())->isValid()) {
460 auto relation = d->relations.at(index.column());
461 if (!relation->isDictionaryInitialized())
462 relation->populateDictionary();
463 if (value.isValid() && !relation->dictionary.contains(value.toString()))
464 return false;
465 }
466 return QSqlTableModel::setData(index, value, role);
467}
468
469/*!
470 Lets the specified \a column be a foreign index specified by \a relation.
471
472 Example:
473
474 \snippet relationaltablemodel/relationaltablemodel.cpp 0
475 \codeline
476 \snippet relationaltablemodel/relationaltablemodel.cpp 1
477
478 The setRelation() call specifies that column 2 in table \c
479 employee is a foreign key that maps with field \c id of table \c
480 city, and that the view should present the \c{city}'s \c name
481 field to the user.
482
483 Note: The table's primary key may not contain a relation to another table.
484
485 \sa relation()
486*/
487void QSqlRelationalTableModel::setRelation(int column, const QSqlRelation &relation)
488{
489 Q_D(QSqlRelationalTableModel);
490 if (column < 0)
491 return;
492 if (d->relations.size() <= column) {
493 const auto oldSize = d->relations.size();
494 d->relations.resize(column + 1);
495 for (auto i = oldSize; i < d->relations.size(); ++i)
496 d->relations[i] = QSharedPointer<QRelation>::create();
497 }
498 d->relations.at(column)->init(this, relation, column);
499}
500
501/*!
502 Returns the relation for the column \a column, or an invalid
503 relation if no relation is set.
504
505 \sa setRelation(), QSqlRelation::isValid()
506*/
507QSqlRelation QSqlRelationalTableModel::relation(int column) const
508{
509 Q_D(const QSqlRelationalTableModel);
510 return d->relations.value(column) ? d->relations.at(column)->rel : QSqlRelation();
511}
512
513QString QSqlRelationalTableModelPrivate::fullyQualifiedFieldName(const QString &tableName,
514 const QString &fieldName) const
515{
516 QString ret;
517 ret.reserve(tableName.size() + fieldName.size() + 1);
518 ret.append(tableName).append(u'.').append(fieldName);
519
520 return ret;
521}
522
523/*!
524 \reimp
525*/
526QString QSqlRelationalTableModel::selectStatement() const
527{
528 Q_D(const QSqlRelationalTableModel);
529
530 if (tableName().isEmpty())
531 return QString();
532 if (d->relations.isEmpty())
533 return QSqlTableModel::selectStatement();
534
535 // Count how many times each field name occurs in the record
536 QHash<QString, int> fieldNames;
537 QStringList fieldList;
538 for (int i = 0; i < d->baseRec.count(); ++i) {
539 QSqlRelation relation = d->relations.value(i) ? d->relations.at(i)->rel : QSqlRelation();
540 QString name;
541 if (relation.isValid()) {
542 // Count the display column name, not the original foreign key
543 name = relation.displayColumn();
544 if (d->db.driver()->isIdentifierEscaped(name, QSqlDriver::FieldName))
545 name = d->db.driver()->stripDelimiters(name, QSqlDriver::FieldName);
546
547 const QSqlRecord rec = database().record(relation.tableName());
548 for (int i = 0; i < rec.count(); ++i) {
549 if (name.compare(rec.fieldName(i), Qt::CaseInsensitive) == 0) {
550 name = rec.fieldName(i);
551 break;
552 }
553 }
554 }
555 else {
556 name = d->baseRec.fieldName(i);
557 }
558 fieldNames[name] = fieldNames.value(name, 0) + 1;
559 fieldList.append(name);
560 }
561
562 QString fList;
563 QString conditions;
564 QString from = SqlrTm::from(tableName());
565 for (int i = 0; i < d->baseRec.count(); ++i) {
566 QSqlRelation relation = d->relations.value(i) ? d->relations.at(i)->rel : QSqlRelation();
567 const QString tableField = d->fullyQualifiedFieldName(tableName(), d->db.driver()->escapeIdentifier(d->baseRec.fieldName(i), QSqlDriver::FieldName));
568 if (relation.isValid()) {
569 const QString relTableAlias = SqlrTm::relTablePrefix(i);
570 QString displayTableField = d->fullyQualifiedFieldName(relTableAlias, relation.displayColumn());
571
572 // Duplicate field names must be aliased
573 if (fieldNames.value(fieldList[i]) > 1) {
574 QString relTableName = relation.tableName().section(QChar::fromLatin1('.'), -1, -1);
575 if (d->db.driver()->isIdentifierEscaped(relTableName, QSqlDriver::TableName))
576 relTableName = d->db.driver()->stripDelimiters(relTableName, QSqlDriver::TableName);
577 QString displayColumn = relation.displayColumn();
578 if (d->db.driver()->isIdentifierEscaped(displayColumn, QSqlDriver::FieldName))
579 displayColumn = d->db.driver()->stripDelimiters(displayColumn, QSqlDriver::FieldName);
580 QString alias = QString::fromLatin1("%1_%2_%3")
581 .arg(relTableName, displayColumn, QString::number(fieldNames.value(fieldList[i])));
582 alias.truncate(d->db.driver()->maximumIdentifierLength(QSqlDriver::FieldName));
583 alias = d->db.driver()->escapeIdentifier(alias, QSqlDriver::FieldName);
584 displayTableField = SqlrTm::as(displayTableField, alias);
585 --fieldNames[fieldList[i]];
586 }
587
588 fList = SqlrTm::comma(fList, displayTableField);
589
590 // Join related table
591 const QString tblexpr = SqlrTm::concat(relation.tableName(), relTableAlias);
592 const QString relTableField = d->fullyQualifiedFieldName(relTableAlias, relation.indexColumn());
593 const QString cond = SqlrTm::eq(tableField, relTableField);
594 if (d->joinMode == QSqlRelationalTableModel::InnerJoin) {
595 // FIXME: InnerJoin code is known to be broken.
596 // Use LeftJoin mode if you want correct behavior.
597 from = SqlrTm::comma(from, tblexpr);
598 conditions = SqlrTm::et(conditions, cond);
599 } else {
600 from = SqlrTm::concat(from, SqlrTm::leftJoin(tblexpr));
601 from = SqlrTm::concat(from, SqlrTm::on(cond));
602 }
603 } else {
604 fList = SqlrTm::comma(fList, tableField);
605 }
606 }
607
608 if (fList.isEmpty())
609 return QString();
610
611 const QString stmt = SqlrTm::concat(SqlrTm::select(fList), from);
612 const QString where = SqlrTm::where(SqlrTm::et(SqlrTm::paren(conditions), SqlrTm::paren(filter())));
613 return SqlrTm::concat(SqlrTm::concat(stmt, where), orderByClause());
614}
615
616/*!
617 Returns a QSqlTableModel object for accessing the table for which
618 \a column is a foreign key, or \nullptr if there is no relation for
619 the given \a column.
620
621 The returned object is owned by the QSqlRelationalTableModel.
622
623 \sa setRelation(), relation()
624*/
625QSqlTableModel *QSqlRelationalTableModel::relationModel(int column) const
626{
627 Q_D(const QSqlRelationalTableModel);
628 if (column < 0 || column >= d->relations.size())
629 return nullptr;
630
631 auto relation = d->relations.at(column);
632 if (!relation || !relation->isValid())
633 return nullptr;
634
635 if (!relation->model)
636 relation->populateModel();
637 return relation->model;
638}
639
640/*!
641 \reimp
642*/
643void QSqlRelationalTableModel::revertRow(int row)
644{
645 QSqlTableModel::revertRow(row);
646}
647
648/*!
649 \reimp
650*/
651void QSqlRelationalTableModel::clear()
652{
653 Q_D(QSqlRelationalTableModel);
654 beginResetModel();
655 d->clearChanges();
656 d->relations.clear();
657 QSqlTableModel::clear();
658 endResetModel();
659}
660
661
662/*! \enum QSqlRelationalTableModel::JoinMode
663
664 \value InnerJoin - Inner join mode, return rows when there is at least one match in both tables.
665 \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).
666
667 \sa QSqlRelationalTableModel::setJoinMode()
668*/
669
670/*!
671 Sets the SQL \a joinMode to show or hide rows with NULL foreign keys.
672 In InnerJoin mode (the default) these rows will not be shown: use the
673 LeftJoin mode if you want to show them.
674
675 \sa QSqlRelationalTableModel::JoinMode
676*/
677void QSqlRelationalTableModel::setJoinMode( QSqlRelationalTableModel::JoinMode joinMode )
678{
679 Q_D(QSqlRelationalTableModel);
680 d->joinMode = joinMode;
681}
682/*!
683 \reimp
684*/
685bool QSqlRelationalTableModel::select()
686{
687 return QSqlTableModel::select();
688}
689
690/*!
691 \reimp
692*/
693void QSqlRelationalTableModel::setTable(const QString &table)
694{
695 Q_D(QSqlRelationalTableModel);
696
697 // memorize the table before applying the relations
698 d->baseRec = d->db.record(table);
699
700 QSqlTableModel::setTable(table);
701}
702
703/*! \internal
704 */
706{
707 for (int i = 0; i < values.count(); ++i) {
708 if (relations.value(i) && relations.at(i)->isValid()) {
709 QVariant v = values.value(i);
710 bool gen = values.isGenerated(i);
711 values.replace(i, baseRec.field(i));
712 values.setValue(i, v);
713 values.setGenerated(i, gen);
714 }
715 }
716}
717
718/*!
719 \reimp
720*/
721bool QSqlRelationalTableModel::updateRowInTable(int row, const QSqlRecord &values)
722{
723 Q_D(QSqlRelationalTableModel);
724
725 QSqlRecord rec = values;
726 d->translateFieldNames(rec);
727
728 return QSqlTableModel::updateRowInTable(row, rec);
729}
730
731/*!
732 \reimp
733*/
734bool QSqlRelationalTableModel::insertRowIntoTable(const QSqlRecord &values)
735{
736 Q_D(QSqlRelationalTableModel);
737
738 QSqlRecord rec = values;
739 d->translateFieldNames(rec);
740
741 return QSqlTableModel::insertRowIntoTable(rec);
742}
743
744/*!
745 \reimp
746*/
747QString QSqlRelationalTableModel::orderByClause() const
748{
749 Q_D(const QSqlRelationalTableModel);
750
751 const QSqlRelation rel = d->relations.value(d->sortColumn) ? d->relations.at(d->sortColumn)->rel : QSqlRelation();
752 if (!rel.isValid())
753 return QSqlTableModel::orderByClause();
754
755 QString f = d->fullyQualifiedFieldName(SqlrTm::relTablePrefix(d->sortColumn), rel.displayColumn());
756 f = d->sortOrder == Qt::AscendingOrder ? SqlrTm::asc(f) : SqlrTm::desc(f);
757 return SqlrTm::orderBy(f);
758}
759
760/*!
761 \reimp
762*/
763bool QSqlRelationalTableModel::removeColumns(int column, int count, const QModelIndex &parent)
764{
765 Q_D(QSqlRelationalTableModel);
766
767 if (parent.isValid() || column < 0 || column + count > d->rec.count())
768 return false;
769
770 for (int i = 0; i < count; ++i) {
771 d->baseRec.remove(column);
772 if (d->relations.size() > column)
773 d->relations.remove(column);
774 }
775 return QSqlTableModel::removeColumns(column, count, parent);
776}
777
778QT_END_NAMESPACE
779
780#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)
Combined button and popup list for selecting options.
QSqlRelationalTableModelSql SqlrTm
QRelatedTableModel * model
bool isDictionaryInitialized() const
QHash< QString, QVariant > dictionary
void init(QSqlRelationalTableModel *parent, const QSqlRelation &relation, int column)