Reputation: 53
According to QxOrm manuals : 3.2 and 3.22, it seems to be possible to use
qx::QxSqlDatabase::getSingleton()->setDatabaseName("./test_qxorm.db");
qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
qx::QxSqlDatabase::getSingleton()->setUserName("root");
qx::QxSqlDatabase::getSingleton()->setPassword("");
separately in every thread to use multiple databases from multiple threads.
But on actually trying to use it, that seems to not be the case for the MONGODB implementation.
Also, on looking at the source for qx::dao::call_query
, it looks like it hasn't been implemented the way other SQL ones have.
Main question : How do I do the same for MONGODB?
QXMONGODB
driver or is it not implemented in any way in QxOrm?Here is an Example in Qt that I tried to check it out.
db_interactor.h
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QJsonDocument>
#include <QObject>
#include <QxOrm.h>
class db_interactor : public QObject
{
Q_OBJECT
public:
explicit db_interactor(QObject *parent = nullptr);
db_interactor(QString configFilename, QObject *parent = nullptr);
signals:
void errorNoReturn (QString errString);
void errorReturn (QString errString);
void initComplete();
void dataReady (QJsonDocument response);
public slots:
void init();
void runQuery();
private:
bool inited = false;
QHash<QString, QString> config;
qx::QxSqlDatabase *db;
};
db_interactor.cpp
#include "db_interactor.h"
db_interactor::db_interactor(QString configFileName, QObject *parent) : QObject{parent}
{
if (!configFileName.isEmpty())
{
//....
config.insert(/*From file*/);
}
//...
}
void db_interactor::init()
{
db = qx::QxSqlDatabase::getSingleton();
qDebug () << "Database Pointer" << db;
db->setDriverName("QXMONGODB");
db->setHostName("localhost");
if (config.contains("DB"))
{
qDebug () << "Setting DB : " << config["DB"];
db->setDatabaseName(config["DB"]);
}
else
{
qDebug () << "_________CONFIG DOES NOT CONTAIN \"DB\"_________________";
db->setDatabaseName("new_db");
}
qDebug () << "____________Initialising DB____________";
qDebug () << db->getDatabase();
inited = true;
emit initComplete();
}
void db_interactor::runQuery()
{
if (inited)
{
qx_query nq ("{\"insert\" : \"some_coll\" , \"documents\" : [{\"a\" : 213}]}");
QSqlError err = qx::dao::call_query(nq);
if (err.isValid())
{
qDebug () << "Error writing to db : " << err.driverText();
emit errorReturn("Error writing to db : " + err.driverText());
}
else
{
emit errorNoReturn("Written to DB");
qx_query bq ("cursor" , "{\"find\" : \"some_coll\"}");
err = qx::dao::call_query(bq);
if (err.isValid())
{
qDebug () << "Error reading from db : " << err.driverText();
emit errorReturn("Error reading from db : " + err.driverText());
return;
}
emit dataReady
(QJsonDocument::fromJson(bq.response().toString().toUtf8()));
}
return;
}
errorReturn ("Not Initialised yet");
}
Creating 2 objects of this class in another QObject class and moving them to separate threads...
mainthingy.h
#include <QObject>
#include <QThread>
#include <QDebug>
#include <QTimer>
#include "db_interactor.h"
class mainThingy : public QObject
{
Q_OBJECT
QThread aFewThreads[2];
public:
explicit mainThingy(QObject *parent = nullptr);
// Ignore the destructor for now, as that is not the point in question
signals:
void init1 ();
void init2 ();
void runQr1 ();
void runQr2 ();
private slots:
void dataFrom1 (QJsonDocument response);
void dataFrom2 (QJsonDocument response);
void showErrReturn (QString err, int thread);
private:
db_interactor *di1, *di2;
void f_init1();
void f_init2();
void f_rq1();
void f_rq2();
void interface();
bool user_time = true;
QTimer ui_timer;
};
mainthingy.cpp
#include "mainthingy.h"
#include <iostream>
#include <string>
mainThingy::mainThingy(QObject *parent)
: QObject{parent}
{
di1 = new db_interactor(QStringLiteral(":/conf1.ini"));
di2 = new db_interactor(QStringLiteral(":/conf2.ini"));
di1->moveToThread(&aFewThreads[0]);
di2->moveToThread(&aFewThreads[1]);
aFewThreads[0].start();
aFewThreads[1].start();
connect(this, &mainThingy::init1, di1, &db_interactor::init);
connect(di1, &db_interactor::initComplete, this, [this]()
{
qDebug () << "DB Interactor 1 Init Complete";
user_time = true;
});
connect(di2, &db_interactor::initComplete, this, [this]()
{
qDebug () << "DB Interactor 2 Init Complete";
user_time = true;
});
connect(this, &mainThingy::init2, di2, &db_interactor::init);
connect(this, &mainThingy::runQr1, di1, &db_interactor::runQuery);
connect(this, &mainThingy::runQr2, di2, &db_interactor::runQuery);
connect(di1, &db_interactor::dataReady, this, &mainThingy::dataFrom1);
connect(di2, &db_interactor::dataReady, this, &mainThingy::dataFrom2);
connect(di1, &db_interactor::errorReturn, this, [this] (QString eS)
{
showErrReturn(eS, 1);
});
connect(di2, &db_interactor::errorReturn, this, [this] (QString eS)
{
showErrReturn(eS, 2);
});
interface();
connect(&ui_timer, &QTimer::timeout, this, [this] ()
{
if (this->user_time)
{
interface();
}
});
ui_timer.start(2000);
}
void mainThingy::dataFrom1(QJsonDocument response)
{
qDebug () << response;
user_time = true;
}
void mainThingy::dataFrom2(QJsonDocument response)
{
qDebug () << response;
user_time = true;
}
void mainThingy::showErrReturn(QString err, int thread)
{
std::cout << "Error in " << thread << ": " << err.toStdString() << std::endl;
qDebug () << "Err " << 1 << err;
user_time = true;
}
void mainThingy::f_init1()
{
qDebug () << "void mainThingy::f_init1()";
emit init1();
}
void mainThingy::f_init2()
{
qDebug () << "void mainThingy::f_init2()";
emit init2();
}
void mainThingy::f_rq1()
{
qDebug () << "void mainThingy::f_rq1()";
emit runQr1();
}
void mainThingy::f_rq2()
{
qDebug () << "void mainThingy::f_rq2()";
emit runQr2();
}
void mainThingy::interface()
{
// Made a crude little CLI to get to the real problem
qDebug () << "void mainThingy::interface()";
std::cout << "Ready for command" << std::endl;
std::string usrResp;
std::cin >> usrResp;
QString uR = QString::fromStdString(usrResp);
if (uR == "i1")
{
f_init1();
user_time = false;
}
else if (uR == "i2")
{
f_init2();
user_time = false;
}
else if (uR == "q1")
{
f_rq1();
user_time = false;
}
else if (uR == "q2")
{
f_rq2();
user_time = false;
}
else if (uR == "quit")
{
exit (0);
}
else
{
std::cout << "?" << std::endl;
qDebug () << "??";
}
}
Having 2 different configurations in qrc:/conf1.ini
and qrc:/conf2.ini
, I expected q1 and q2 to send data to 2 separate databases.
But, I found out the following:
qx::QxSqlDatabase::getSingleton()->getDatabase()
gave an error and a null databasedi1
, the query worked fine and inserted data into the correct database, but on initialising di2
in the same program instance, I found both queries "q1"
and "q2"
inserting data into the database initialised by di2
. Essentially, the same configuration is being overwritten.Upvotes: 0
Views: 124
Reputation: 53
Using multiple databases in QxOrm has 2 ways to be used in case of SQL Databases.
QSqlDatabase
and pass a pointer when calling the setXXXX() functions and use that object when calling queries.true
for bJustForCurrentThread
when calling the setXXXX() functions and QxOrm will handle it according to the documentation.void setDriverName(const QString & s, bool bJustForCurrentThread = false, QSqlDatabase * pJustForThisDatabase = NULL);
void setDatabaseName(const QString & s, bool bJustForCurrentThread = false, QSqlDatabase * pJustForThisDatabase = NULL);
void setHostName(const QString & s, bool bJustForCurrentThread = false, QSqlDatabase * pJustForThisDatabase = NULL);
void setPort(int i, bool bJustForCurrentThread = false, QSqlDatabase * pJustForThisDatabase = NULL);
In case of QXMONGODB
driver, you have the option of opening multiple databases in different threads and as long as you pass true
for bJustForCurrentThread
when calling the setXXXX() functions, it will work as expected.
In the above question I had not passed true
in the argument bJustForCurrentThread
, which caused configuration in any one application thread to be set for all the other threads, giving the problems that I was having.
Conclusions:
QSqlDatabase
won't be usable with MONGODB driver as QSqlDatabase
is for SQL Databasescall_query()
implementation for MONGODB seems to be different on the top, but the internal implementation still has the required support for multiple databases in different threads.Upvotes: 0