目前,我有以下代码:
main.cpp中
#include "mainwindow.h" #include "database.h" #include <QApplication> int main(int argc,char *argv[]) { QApplication a(argc,argv); Database db; MainWindow w; if(db.createStructure()) { w.show(); } return a.exec(); }
database.h
#ifndef DATABASE_H #define DATABASE_H #include <QObject> #include <QsqlDatabase> class Database : public QObject { Q_OBJECT public: explicit Database(QObject *parent = 0); // FUNCTIONS bool createStructure(); signals: public slots: private: // VARIABLES QsqlDatabase m_db; // FUNCTIONS bool open(); void close(); bool transaction(); bool commit(); }; #endif // DATABASE_H
database.cpp
#include "database.h" #include <QCoreApplication> #include <QsqlDatabase> #include <QsqlQuery> #include <QsqlError> #include <QList> Database::Database(QObject *parent) : QObject(parent) { m_db = QsqlDatabase::addDatabase("QsqlITE"); m_db.setHostName("localhost"); m_db.setDatabaseName(QCoreApplication::applicationDirPath() + "/events.db"); } // PRIVATE bool Database::open() { return m_db.open(); } void Database::close() { return m_db.close(); } bool Database::transaction() { return m_db.transaction(); } bool Database::commit() { return m_db.commit(); } // PUBLIC bool Database::createStructure() { bool prepared; QList<QString> commands; commands.append("CREATE TABLE...;"); commands.append("CREATE TABLE...;"); commands.append("CREATE TABLE...;"); if (!Database::open()) { return false; } else { if (!Database::transaction()) { Database::close(); return false; } else { foreach(QString command,commands) { QsqlQuery query; prepared = query.prepare(command); if(!prepared) { if (!Database::commit()) { Database::close(); return false; } else { Database::close(); return false; } } else { if(!query.exec()) { if (!Database::commit()) { Database::close(); return false; } else { Database::close(); return false; } } } } if (!Database::commit()) { Database::close(); return false; } else { Database::close(); return true; } } } }
这段代码正在运行.
但是,QsqlITE数据库不是一次添加到m_db对象,而是每次调用类中的函数时,因为……
Database::Database(QObject *parent) : QObject(parent) { m_db = QsqlDatabase::addDatabase("QsqlITE"); m_db.setHostName("localhost"); m_db.setDatabaseName(QCoreApplication::applicationDirPath() + "/events.db"); }
…每次执行代码块.
当前的默认连接只是被替换,因为新的连接是相同的,这对程序没有任何影响,但它看起来不像一个简洁的解决方案.
所以我试着用一个声明函数替换这个代码块,我可以从main.cpp调用一次…
main.cpp中
int main(int argc,argv); Database db; MainWindow w; db.declare(“QsqlITE”,“localhost”,QCoreApplication::applicationDirPath() + "/events.db"); if(db.createStructure()) { w.show(); } return a.exec(); }
database.cpp
void Database::declare(QString driver,QString host,QString path) { m_db = QsqlDatabase::addDatabase(driver); m_db.setHostName(host); m_db.setDatabaseName(path); }
…但是m_db对象的值当然只能在declare-function中使用,而不能用于我之后调用的其他函数.
我对解决方案的最佳猜测是在main.cpp中声明QsqlDatabase并将其提供给它应该调用的函数:
main.cpp中
int main(int argc,argv); QsqlDatabase qdb = QsqlDatabase::addDatabase("QsqlITE"); qdb.setHostName("localhost"); qdb.setDatabaseName(QCoreApplication::applicationDirPath() + "/events.db"); Database db; MainWindow w; if(db.createStructure(qdb)) { w.show(); } return a.exec(); }
database.cpp
bool Database::open(QsqlDatabase qdb) { return qdb.open(); } void Database::close(QsqlDatabase qdb) { return qdb.close(); } bool Database::transaction(QsqlDatabase qdb) { return qdb.transaction(); } bool Database::commit(QsqlDatabase qdb) { return qdb.commit(); } bool Database::createStructure(QsqlDatabase qdb) { bool prepared; QList<QString> commands; commands.append("CREATE TABLE...;"); commands.append("CREATE TABLE...;"); commands.append("CREATE TABLE...;"); if (!Database::open(qdb)) { return false; } else { if (!Database::transaction(qdb)) { Database::close(qdb); return false; } else { foreach(QString command,commands) { QsqlQuery query; prepared = query.prepare(command); if(!prepared) { if (!Database::commit(qdb)) { Database::close(qdb); return false; } else { Database::close(qdb); return false; } } else { if(!query.exec()) { if (!Database::commit(qdb)) { Database::close(qdb); return false; } else { Database::close(qdb); return false; } } } } if (!Database::commit(qdb)) { Database::close(qdb); return false; } else { Database::close(qdb); return true; } } } }
是否有可能以某种方式在类中存储可重用的QsqlDatabase对象?如果是这样,怎么样?
真的很感谢你的帮助!
编辑1
mainwindows.cpp
void MainWindow::on_pushButton_24_clicked() { Database db; bool b = db.createStructure(); QMessageBox::information(this,"test",QString(b)); }
解决方法
免责声明:我没有编译我的任何建议,如果有语法错误,请原谅我.
首先,你可能正在寻找的是Singleton Pattern(我不再那么喜欢了,但为了你的目的,人们可以说它可以被认为是合适的):
您必须在类定义中包含以下内容:
class Database : public QObject { Q_OBJECT public: static Database* instance(); private: static Database* m_instance; Database(); ~Database() {}; // it can be necessary to have this public in some cases,if // you ever get a linker error related to deletion,this is // probably the reason. public: // FUNCTIONS ... };
// init singleton pointer to NULL Database* Database::m_instance = NULL; Database* Database::instance() { if( !m_instance ) { m_instance = new Database(); } return m_instance; }
然后,您可以使用例如访问该单例
if( Database::instance()->createStructure() ) { w.show(); }
这是做什么的?在程序开始时,该行
Database* Database::m_instance = NULL;
将m_instance变量初始化为NULL.第一次调用Database :: instance()时,它意识到m_instance仍为NULL并创建一个新对象并使m_instance指向该对象.从那时起,将始终返回指向该对象的指针,但不会再创建数据库对象.
在createStructure()函数中,即使出现错误,也可以提交数据库.通常的过程是在成功时commit()并在失败时回滚().
在修复之前,请务必阅读下一点:
我建议的第三件事是,每当你看到多次出现相同的行时,就会习惯于怀疑.这通常会引发子功能.
我在说
Database::close(); return false;
看看我如何通过引入另一个方法重写你的createStructure()方法,并将else {}留在不需要的地方:
bool Database::createStructure() { QStringList commands; commands.append("CREATE TABLE...;"); commands.append("CREATE TABLE...;"); commands.append("CREATE TABLE...;"); if (!Database::open()) return false; // at this point you can be sure the database is open if (!Database::transaction()) { Database::close(); return false; } // at this point you can be sure the database is open and a transaction was started if (!Database::executeCommands(commands)) { // an error occurred - we need to rollback what we did so far Database::rollback(); Database::close(); return false; } // everything was executed properly,but the transaction is still active // => commit the changes we've made bool committed = Database::commit(); // no matter if the commit was successful or not,close the database,// then return the result we've stored Database::close(); return committed; } bool Database::executeCommands(const QStringList& commands) { // This method simply executes the queries and is relieved from // transaction-related code. foreach(QString command,commands) { QsqlQuery query; bool prepared = query.prepare(command); if(!prepared) return false; if(!query.exec()) return false; } return true; }
这可以进一步重构,它只是使代码更容易遵循的一个例子,因此通常不易出错.