Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-140184

Clarification Request: QSqlRelationalTableModel::fieldIndex() Behavior After setRelation() and select()

XMLWordPrintable

    • macOS, Windows

      Issue Overview

      When a relationship to another table is set on a QSqlRelationalTableModel instance using setRelation(), and select() is called, the calling fieldIndex() starts to fail with the initial fieldName.
      This is considered behavior consistent with the specification; however, to make it easier for users to understand, this report requests an addition to the documentation for clarification.

      Example Behavior Before and After select()

      For example, when running the attached sample program, immediately after calling setRelation(), the original field names can still be used to obtain indexes:

       

      -----showTableInfo (modelB, recordB) after setRelaton() -----
      Record Field ( 0 ):  "id"
      Record Field ( 1 ):  "some_data"
      Record Field ( 2 ):  "ref_data_a1"
      Record Field ( 3 ):  "ref_data_a2"
      FieldName ( "id" ):  model->fieldIndex 0 , Record Field Index:  0
      FieldName ( "some_data" ):  model->fieldIndex 1 , Record Field Index:  1
      FieldName ( "ref_data_a1" ):  model->fieldIndex 2 , Record Field Index:  2
      FieldName ( "ref_data_a2" ):  model->fieldIndex 3 , Record Field Index:  3
      Column ( 2 ) Relation:  [Table: "table_a" , Index Column: "id" , Display Column: "name" ]
        model->headerData : "ref_data_a1"
        record.fieldName : "ref_data_a1"
      Column ( 3 ) Relation:  [Table: "table_a" , Index Column: "id" , Display Column: "name" ]
        model->headerData : "ref_data_a2"
        record.fieldName : "ref_data_a2"   

       

       

      However, after calling select(), the model can no longer obtain indexes with the same field names:

       

      -----showTableInfo start (modelB, recordB) after select() -----
      Record Field ( 0 ):  "id"
      Record Field ( 1 ):  "some_data"
      Record Field ( 2 ):  "ref_data_a1"
      Record Field ( 3 ):  "ref_data_a2"
      FieldName ( "id" ):  model->fieldIndex 0 , Record Field Index:  0
      FieldName ( "some_data" ):  model->fieldIndex 1 , Record Field Index:  1
      FieldName ( "ref_data_a1" ):  model->fieldIndex -1 , Record Field Index:  2
      FieldName ( "ref_data_a2" ):  model->fieldIndex -1 , Record Field Index:  3
      Column ( 2 ) Relation:  [Table: "table_a" , Index Column: "id" , Display Column: "name" ]
        model->headerData : "table_a_name_2"
        record.fieldName : "ref_data_a1"
      Column ( 3 ) Relation:  [Table: "table_a" , Index Column: "id" , Display Column: "name" ]
        model->headerData : "name"
        record.fieldName : "ref_data_a2"   

       

       

      Explanation of the Mechanism

      I believe this behavior is caused by the following mechanism:

      1. The issue in question concerns the behavior of calling fieldIndex(const QString &fieldName) in the QSqlRelationalTableModel class that is used to provide data to a view class.
      2. Although the parameter of fieldIndex() is named "fieldName", the QSqlRelationalTableModel class does not actually have a member called fieldName. In practice, it refers to headerData.
      3. headerData is the string displayed as the header when the data is shown in a view. Therefore, when a relation is set with setRelation(), headerData is replaced with the name of the referenced field from the related table.
      4. At this point, if multiple relations are set that reference the same field in the same table, headerData values become duplicated. In such cases, automatically generated names (consisting of the referenced table name + field name + a sequence number) are used for the duplicates.

      The phenomenon in question is the result of 3 and 4 above and is considered expected behavior according to Qt SQL specifications. However, because Qt’s official documentation lacks sufficient detail on this matter, it led to confusion.

       

      Proposed changes to the documentation

      The red part is the text I propose to add.

       

      int QSqlTableModel::fieldIndex(const QString &fieldName) const

      Returns the index of the field fieldName, or -1 if no corresponding field exists in the model.

      In actual behavior, the method refers to headerData using fieldName as the key, and if a match is found, it returns the corresponding index. 

       

      void QSqlRelationalTableModel::setRelation(int column, const QSqlRelation &relation)

      Lets the specified column be a foreign index specified by relation.

      Example:

          model->setTable("employee");

          model->setRelation(2, QSqlRelation("city", "id", "name"));

      The setRelation() call specifies that column 2 in table employee is a foreign key that maps with field id of table city, and that the view should present the city's name field to the user.

      Note: The table's primary key may not contain a relation to another table.

      Note: When a relation is set using setRelation() and select(), the headerData is replaced with the name of the referenced field from the related table. If multiple relations reference the same table and field, duplicate header strings are avoided by automatically generating unique names in the format: referenced table name + field name + sequence number. In such cases, the original FieldName can no longer be used as a key to obtain the index. Therefore, if the index value is required for subsequent processing, it must be retrieved and stored before calling select().

        1. testdb2.zip
          44 kB
          Hitoshi Ito
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

            chehrlic Christian Ehrlicher
            hitoshiito Hitoshi Ito
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:

                There are no open Gerrit changes