3

I am accessing a MySQL 5.6 database using Qt 5.3.1 SQL module. Currently I try to move some of that code from the main thread to a custom thread to allow the GUI thread to stay responsive during DB updates.

I understood that everything (including establishing of the connection) must be moved to the custom thread. I am using queued signals and slots to achieve this and it works properly.

However there is one thing I am not sure about: How can I return query results back to main thread? Of course I will use a signal for that. But what kind of object should I return in that signal?

Should I return the QSqlQuery? I suppose this will be dangerous since QSqlQuery is attached to the connection/database in some way.

Should I return a list of QSqlRecord objects taken from the query using record()? Unfortunately the documentation does not say a word if this is safe.

What is the right container/way to safely return the results?

Silicomancer
  • 8,604
  • 10
  • 63
  • 130
  • Hi ! To my mind, OO speaking, if you have a thread which manage every interaction with your database, you should leave every sql objects in this part of code. With a database you extract some data so why not transfer these data throw signal/slot ? Don't know if I have to speak about pointer/reference or value here. – Martin Sep 11 '14 at 06:30
  • I would like to create a generic QThread derived query thread class that should be able to return generic results, independent from the actually used SQL statement. – Silicomancer Sep 11 '14 at 06:33

1 Answers1

1

If, for example, the database contained personal details, you could create a separate class, derived from QObject: -

class Person : public QObject
{
    Q_OBJECT

    public:
        Person();

    private:
        QString m_firstName;
        QString m_surname;
        QString m_address
        QDateTime m_dateOfBirth;
};

Then, having registered its metadata for using with signals and slots, retrieve the database record, populate the Person object and send it with signals and slots. The classes you create can then represent the tables in the database.

However, a much simpler method would be to use a QMap and emit a signal with that instead: -

QMap personMap;
personMap["name"] = sqlRecord.value().toString("name");
personMap["surname"] = sqlRecord.value().toString("surname");
personMap["address"] = sqlRecord.value().toString("address");
...etc

It may be a good idea to emit a function that takes a token and the map, where the token denotes the type of information that the map contains:-

emit RetrievedData("Person", personMap);

I would avoid sending the SqlRecord or anything to do with the underlying method of storing the data. It's always good to use loosely coupled classes. This way, you could decide to replace the database storage with another mechanism, without having to refactor all the other code.

----------- In response to comments ------------

Populate a map with the sql record. For simplicity, we assume all returned items are strings. If record items are numbers, simply convert to string before storing in the map.

QMap PopulateMap(SQLRecord& sqlRecord)
{
    QMap map;

    for(int i=0; i<sqlRecord.count(); ++i)
    {
        map[sqlRecord.fieldName(i)] = sqlRecord.value(i).toString();
    }

    return map;
}
Community
  • 1
  • 1
TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
  • I see your point. But this way I would need to implement a new SQL threading class for each statement (even if there only few differences). I hoped I could create a generic, reusable class. – Silicomancer Sep 11 '14 at 08:36
  • @Silicomancer, sorry but I don't see what you mean. You have one separate thread that carries out the SQL queries. When it receives results, it emits a signal with the data, either wrapped in a class, or just stored in a QMap. Why would you need multiple SQL threading classes, or have you created a query class that inherits from QThread? – TheDarkKnight Sep 11 '14 at 08:44
  • Regarding your "class Person" proposal: Different statements return different data. I would need a specific signal (and so a specific class) for each SQL statement. Regarding your "QMap personMap" proposal: The signal would always be the same but still I would need a specific class that can do the record-to-map conversion for each statement. – Silicomancer Sep 11 '14 at 08:57
  • Why would you need a specific class? You can create a single function which retrives the count from the SQLRecord, then iterates through them getting each fieldName by index and appropriate value and storing them in the map - see the edited answer. – TheDarkKnight Sep 11 '14 at 09:07
  • So how would the thread know about that conversion function? Supplying a function pointer or functor? I could probably do this. Currently I am thinking about a third way. I could write a generic thread class but supply a specific worker to it that uses your ideas. This also would allow optional synchronous access using the worker without a thread. – Silicomancer Sep 11 '14 at 09:12
  • Yes, I use QThread as a base class for a QueryThread class. And I am using a QObject derived QueryWorker. Both are currently generic. – Silicomancer Sep 11 '14 at 09:18
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/61039/discussion-between-merlin069-and-silicomancer). – TheDarkKnight Sep 11 '14 at 09:43