首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Qt:类中的QSqlDatabase对象(如何声明?)

Qt:类中的QSqlDatabase对象(如何声明?)
EN

Stack Overflow用户
提问于 2013-02-15 08:32:10
回答 1查看 2.9K关注 0票数 4

我正在尝试创建一个类,它应该处理来自sqlite数据库的所有数据。但是,我对QT和C++非常陌生,我想知道类中数据库对象的声明。我可能需要一些关于我做的对和错的建议,以及它通常应该或可以如何做。我的目标是为类创建一个QSqlDatabase,并将其用于类中的每个函数。

目前,我有以下代码:

main.cpp

代码语言:javascript
运行
复制
#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

代码语言:javascript
运行
复制
#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

代码语言:javascript
运行
复制
#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对象中,而是每次调用类中的函数时,因为.

代码语言:javascript
运行
复制
Database::Database(QObject *parent) :
    QObject(parent)
{
    m_db = QSqlDatabase::addDatabase("QSQLITE");
    m_db.setHostName("localhost");
    m_db.setDatabaseName(QCoreApplication::applicationDirPath() + "/events.db");
}

每次都执行...codeblock。当前的默认连接刚刚被替换,因为新的连接是相同的,这对程序没有任何影响,但它看起来不像是一个整洁的解决方案。

所以我试着用一个可以从main.cpp调用的声明函数替换这个代码块.

main.cpp

代码语言:javascript
运行
复制
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Database db;
    MainWindow w;

    db.declare(“QSQLITE”, “localhost”, QCoreApplication::applicationDirPath() + "/events.db");

    if(db.createStructure())
    {
        w.show();
    }

    return a.exec();
}

database.cpp

代码语言:javascript
运行
复制
void Database::declare(QString driver, QString host, QString path)
{
    m_db = QSqlDatabase::addDatabase(driver);
    m_db.setHostName(host);
    m_db.setDatabaseName(path);
}

...but - m_db对象的值当然只能在声明函数中使用,而不能用于我随后调用的其他函数。

我对解决方案的最佳猜测是在main.cpp中声明main.cpp并将其交给它应该调用的函数:

main.cpp

代码语言:javascript
运行
复制
int main(int argc, char *argv[])
{
    QApplication a(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

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
void MainWindow::on_pushButton_24_clicked()
{
    Database db;
    bool b = db.createStructure();

    QMessageBox::information(this, "test", QString(b));
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-02-15 14:46:31

我会坚持你的原始代码来解释。

免责声明:我没有编译我的任何建议,如果有语法错误请原谅。

首先,您可能需要的是单例模式 (我不再那么喜欢它了,但就您的目的而言,可以说它可以被认为是合适的):

在您的类定义中必须有以下内容:

代码语言:javascript
运行
复制
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
    ...
};

以及.cpp文件中的以下内容:

代码语言:javascript
运行
复制
// init singleton pointer to NULL
Database* Database::m_instance = NULL;

Database* Database::instance()
{
    if( !m_instance )
    {
        m_instance = new Database();
    }
    return m_instance;
}

然后,您可以访问该单例使用。

代码语言:javascript
运行
复制
if( Database::instance()->createStructure() )
{
    w.show();
}

这是干什么用的?在程序开始时,行

代码语言:javascript
运行
复制
Database* Database::m_instance = NULL;

将m_instance变量初始化为NULL。第一次调用Database::instance()时,它会意识到m_instance仍然是空的,并创建了一个新对象,并使m_instance指向该对象。从那时起,指向该对象的指针将始终被返回,但不会创建更多的Database对象。

在您的createStructure()函数中,即使有错误,也可以使用commit()数据库。通常的程序是在成功时使用commit(),在失败时使用rollback()。在解决这个问题之前,请务必阅读下一点:

我建议的第三件事是,每当你经常看到相同行的多次出现时,就习惯于怀疑。通常需要一个子函数。

我说的是

代码语言:javascript
运行
复制
Database::close();
return false;

看看我是如何通过引入另一个方法来重写您的createStructure()方法的,并且在没有必要的地方省略了else{ }

代码语言:javascript
运行
复制
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;
}

这可以进一步重构,这只是一个例子,使您的代码更容易遵循,因此通常不容易出错。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14890751

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档