从QThread返回QSqlQuery结果

时间:2022-06-20 10:50:58

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.

我正在使用Qt 5.3.1 SQL模块访问MySQL 5.6数据库。目前,我尝试将一些代码从主线程移动到自定义线程,以允许GUI线程在数据库更新期间保持响应。

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.

我应该返回QSqlQuery吗?我认为这将是危险的,因为QSqlQuery以某种方式附加到连接/数据库。

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.

我应该使用record()返回从查询中获取的QSqlRecord对象列表吗?不幸的是,如果这是安全的,那么文档就不会说一句话。

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

什么是安全返回结果的正确容器/方式?

1 个解决方案

#1


1  

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

例如,如果数据库包含个人详细信息,则可以创建一个从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.

然后,注册其元数据以使用信号和插槽,检索数据库记录,填充Person对象并使用信号和插槽发送它。然后,您创建的类可以表示数据库中的表。

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

然而,一个更简单的方法是使用QMap并用它发出信号: -

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.

我会避免发送SqlRecord或与存储数据的基础方法有关的任何事情。使用松散耦合的类总是好的。这样,您可以决定使用其他机制替换数据库存储,而无需重构所有其他代码。

----------- 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.

使用sql记录填充映射。为简单起见,我们假设所有返回的项都是字符串。如果记录项是数字,只需在存储到地图之前转换为字符串。

QMap PopulateMap(SQLRecord& sqlRecord)
{
    QMap map;

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

    return map;
}

#1


1  

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

例如,如果数据库包含个人详细信息,则可以创建一个从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.

然后,注册其元数据以使用信号和插槽,检索数据库记录,填充Person对象并使用信号和插槽发送它。然后,您创建的类可以表示数据库中的表。

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

然而,一个更简单的方法是使用QMap并用它发出信号: -

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.

我会避免发送SqlRecord或与存储数据的基础方法有关的任何事情。使用松散耦合的类总是好的。这样,您可以决定使用其他机制替换数据库存储,而无需重构所有其他代码。

----------- 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.

使用sql记录填充映射。为简单起见,我们假设所有返回的项都是字符串。如果记录项是数字,只需在存储到地图之前转换为字符串。

QMap PopulateMap(SQLRecord& sqlRecord)
{
    QMap map;

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

    return map;
}