Russian Qt Forum
Март 28, 2024, 15:02 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Работа с БД в отдельном потоке  (Прочитано 8105 раз)
INZER
Новичок

Offline Offline

Сообщений: 20


Просмотр профиля
« : Май 30, 2022, 16:50 »

Решил вынести работу с базой данных в отдельный поток

Приложение строится на архитектуре Model-View-Presenter
В модели БД воркер (SqlWorker ниже), агрегирующий класс-исполнитель запросов (SqlQueryExecutor)
Код:

class SqlWorker : public QObject
{
    Q_OBJECT
public:
    explicit SqlWorker(QObject *parent = nullptr);
    ~SqlWorker ();

    void addDbServer (QString serverName, QHostAddress address);
    QList <QString> getDbServers ();

    QString getLastUsedDbName () { return currentDbName; }
    bool openDbConnection(QString serverName, QString login, QString password);
private:
    QString currentDbName;
    QHash<QString, QHostAddress> dbServers;

    QThread * executorThread;
    SqlQueryExecutor * executor;

signals:
    void stopExecutor ();
    void executorOpenDbConnection (QString, QString, QString, QString);
    void dbErrorOccured (STATE, QString, QString, bool);

private slots:
    void slotHandleDbError (qint8 error, QString errorDescription, QString dbName);
    void slotDbConnected (QString);

};

class SqlQueryExecutor : public QObject
{
    Q_OBJECT
public:
    explicit SqlQueryExecutor(QObject *parent = nullptr);
    ~SqlQueryExecutor ();
private:
    const QString strQueryA618;
    QString strWhereA618;
    A618SqlModel * model618;

    void changeModel618 (const QString& query);

signals:
    void dbConnected (QString);
    void dbDbErrorAppears (qint8 error, QString errorDescription, QString dbName);
    void return618Data (A618SqlModel & model);
    void finished ();

public slots:
    void slotStartExecutorThread ();
    void slotStopExecutorThread ();

    void slotOpenDbConnection (QString adress, QString serverName, QString login, QString password);
    void slotGet618Messages (unsigned int turplesLimit);
};

class A618SqlModel : public QSqlQueryModel
{
    Q_OBJECT

public:
    A618SqlModel(QObject *parent = 0);
    QVariant data(const QModelIndex &index, int role) const;
};

Q_DECLARE_METATYPE(A618SqlModel)

Проблема в том что ранее в однопоточном исполнении результат выполнения запроса попадал в модель A618SqlModel, котрая успешно скармливалась QtableView

Однако сейчас я не могу передать результат выполения запроса, так как не могу использовать A618SqlModel для передачи в виде параметра сигнала (не могу зарегистрировать его как метатип, потому что конструктор копирования закрыт).

Подскажите пожалуйста как правильно в Qt правильно передать результат выполния запроса к БД из другого потока.

Код:
QObject::connect(modelObject, SIGNAL(return618Data(A618SqlModel &)), this, SLOT(slotSet618Messages(A618SqlModel &)));

Код:
    qRegisterMetaType<A618SqlModel>();

Заранее спасибо
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 861


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #1 : Май 30, 2022, 17:18 »

Может, сделать наоборот - в вокер передать ссылку на TableView? Проблем с совместным использованием, вроде, не наблюдается.
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
INZER
Новичок

Offline Offline

Сообщений: 20


Просмотр профиля
« Ответ #2 : Май 30, 2022, 21:47 »

Спасибо, завтра обязательно попробую,
Была такая мысль, но сомневался в корректности доступа к табличке из другого потока.

Единственное что смущает - не нашел что у QTableView реализован конструктор копирования, как я понимаю без него  не получится зарегистрироовать мета тип и, соответственно, установить коннекты между методами объектов.
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 861


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #3 : Май 30, 2022, 22:00 »

Вы не поняли - я предлагаю использовать TableView из того потока, где вы работаете с базой. Т.е. в конструкторе вокера предусматриваете ссылку на вьюшник, ну и в конструкторе делаете tableView-> setModel(model618).
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
INZER
Новичок

Offline Offline

Сообщений: 20


Просмотр профиля
« Ответ #4 : Май 31, 2022, 07:11 »

Дело в том что у меня ~20 вью в которые необходимо отдавать результаты запросов. Не хочется хранить ссылки на вью в модели. Согласно архитектуре Model View Presenter отображение и модель не должны быть связаны друг с другом никак. Потому хочется прокидывать результат. Ну либо ссылку на требуемую вью непосредственно при запросе.
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 861


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #5 : Май 31, 2022, 09:09 »

Да хоть 40, какая разница? Массив указателей, в отдельном методе установка модели. Не понимаю проблемы. Но хозяин - барин...
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
INZER
Новичок

Offline Offline

Сообщений: 20


Просмотр профиля
« Ответ #6 : Май 31, 2022, 09:16 »

Ни в коем случае не ругаюсь на ваше предложение, огромное спасибо за подсказку, не думал о таком решении, так как мыслил в связи с выбранной архитектурой. Реализую как временное решение.

Может кто то еще подскажет решения как из потока получить данные из БД.
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 861


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #7 : Май 31, 2022, 09:45 »

так как мыслил в связи с выбранной архитектурой.
Архитектура тут не виновата Подмигивающий

Может кто то еще подскажет решения как из потока получить данные из БД.
Еще как подскажут, жалеть будете, что спросили Улыбающийся
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
INZER
Новичок

Offline Offline

Сообщений: 20


Просмотр профиля
« Ответ #8 : Июнь 01, 2022, 16:02 »

Если кому то вдруг пригодится через СИГНАЛ-СЛОТ можно прокидвать указатели на любые типы данных Улыбающийся Прокидываю указатель на QSqlQuery
Тему можно считать закрытой
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 861


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #9 : Июнь 01, 2022, 22:11 »

Не очень понятно, что вы сделали, но имейте в виду, что подключение к БД может быть использовано только в том потоке, в котором оно было создано.
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
INZER
Новичок

Offline Offline

Сообщений: 20


Просмотр профиля
« Ответ #10 : Июнь 01, 2022, 23:20 »

Да, спасибо я знаю

Результат возвращаю во вью через указатель на QSqlQuery

Код:
void SqlQueryExecutor::slotGet618Data(uint turplesCount)
{
    if (!QSqlDatabase::database().isOpen())
    {
        emit dbDbErrorAppears(QSqlError::ConnectionError, tr("Ошибка подключения к БД."), "");
        return;
    }
    QSqlQuery * query618 = new QSqlQuery ();
    QString sty;
    if (turplesCount == 0)
        sty = QString ("%1 %2 ORDER BY id DESC ").arg(strQueryA618, strWhereA618);
    else
        sty = QString ("%1 %2 ORDER BY id DESC %3 %4").arg(strQueryA618, strWhereA618, "LIMIT").arg(turplesCount);
    query618->exec(sty);
    if (query618->lastError().isValid())
    {
        emit dbDbErrorAppears(query618->lastError().type(), query618->lastError().text(), "");
        return;
    }
    emit set618Data(query618);
}
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 861


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #11 : Июнь 02, 2022, 08:31 »

Как я понял, модель у вас в гуёвом потоке? Так делать нельзя по той причине, о которой я вам напоминал.
Другой вопрос, можно ли перенести модель в поток БД и использовать ее для нескольких представлений, существующих в основном потоке? Не уверен, может, коллеги что подскажут?

Upd. Да, собственно, и не нужны подсказки. Тут простая логика - модель должна быть одна, связана с источником данных (БД) и находиться в потоке БД. Представлений может быть много и находиться они в любом потоке. Так что см. мой первый совет.
« Последнее редактирование: Июнь 02, 2022, 14:27 от sergek » Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
diten
Новичок

Offline Offline

Сообщений: 1


Просмотр профиля
« Ответ #12 : Июнь 21, 2022, 08:20 »

Нужно в том потоке создавать динамически экземпляр модели.
В методе инициализации окна:
connect(ссылка_на_объект_класса_потока_работающего_с_БД, SIGNAL(resultReady(QSqlQueryModel*)), this, SLOT(completeModel(QSqlQueryModel*)));
В определение класса, который работает с БД:
  QSqlQueryModel *model;
В методе run():
  model = new QSqlQueryModel();
  model->setQuery(qry, db);
  emit resultReady(this->model);
Это решение вашей проблемы. Но, есть в этом подводный камень, иногда выносит ошибку во время присвоения модели в QTableView. Пока в поисках, как это сделать правильно
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.049 секунд. Запросов: 22.