【问题标题】:Commit changes to SQLite database, that can be seen between QTabs提交对 SQLite 数据库的更改,可以在 QTab 之间看到
【发布时间】:2016-06-02 03:40:12
【问题描述】:

我有一个简单的应用程序,我可以在其中登录/注销用户。当用户登录时,应用程序会在主窗口(员工/管理员/客户)上显示相应的选项卡。我有一个QMainWindow,上面有QTabWidget。在我的QMainWindow 中,我创建了一个数据库(为此我实现了一个特殊的类):

class DataBase
{
public:

    DataBase();

    void initDatabase();
    void closeDatabase();

private:

    QSqlDatabase db;
};

DataBase::DataBase()
{
}

void DataBase::initDatabase()
{
    QString filename = "database.sql";
    QFile file(filename);

    db = QSqlDatabase::addDatabase("QSQLITE");
    db.setHostName("localhost");
    db.setDatabaseName(filename);

    // create users table
    if(this->db.open())
    {
        QSqlQuery usersTableQuery;
        QString usersTableQueryStr = "CREATE TABLE IF NOT EXISTS USERS (ID INTEGER PRIMARY KEY NOT NULL, "
                                 "LOGIN TEXT,"
                                 "PASSWORD TEXT,"
                                 "FIRSTNAME TEXT,"
                                 "LASTNAME TEXT,"
                                 "EMAIL TEXT,"
                                 "ACCOUNT_TYPE INTEGER" 
                                 ");";

        if(usersTableQuery.exec(usersTableQueryStr))
        {
            qDebug() << "Create USERS table OK";
        }
        else
        {
            qDebug() << usersTableQuery.lastError().text();
        }
    }
    else
    {
        qDebug() << "DB is not opened!\n";
    }

    // create service table
    if(this->db.open())
    {
        QSqlQuery serviceTableQuery;
        QString serviceTableQueryStr = "CREATE TABLE IF NOT EXISTS SERVICE (ID INTEGER PRIMARY KEY NOT NULL, "
                                 "NAME TEXT,"
                                 "PRICE REAL"
                                 ");";
        if(serviceTableQuery.exec(serviceTableQueryStr))
        {
            qDebug() << "Create SERVICE table OK";
        }
        else
        {
            qDebug() << serviceTableQuery.lastError().text();
        }
    }
    else
    {
        qDebug() << "DB is not opened!\n";
    }
}

void DataBase::closeDatabase()
{
    db.close();
}

我的员工、管理员、客户标签如下所示:

class AdminTab : public QWidget
{
    Q_OBJECT
public:
    explicit AdminTab(DataBase *db, QWidget *parent = 0);
//...

每个人(员工、客户、管理员)都可以在数据库中进行更改(例如,管理员可以插入服务,用户可以检查可用服务等)。但是,当管理员添加服务(我在打开的数据库上进行插入操作)并注销时,当客户端登录时,它看不到管理员所做的更改。当我再次启动应用程序,并且客户端登录时,它可以看到新添加的服务。

添加服务如下所示:

bool DataBase::insertService(QString name, double price)
{
    if(!db.isOpen())
    {
        qDebug() << query.lastError();
        return false;
    }
    else
    {
        QSqlQuery query;
        query.prepare("INSERT INTO SERVICE (NAME, PRICE) "
                      "VALUES (:NAME, :PRICE)");
        query.bindValue(":NAME", name);
        query.bindValue(":PRICE", price);

        if(query.exec())
        {
            return true;
        }
        else
        {
            qDebug() << query.lastError();
        }
    }
    return false;
}

我猜这是数据库一直处于打开状态的问题,但是如何在我在数据库中插入/删除某些内容后使更改可用?我在创建 QMainWindow 时打开数据库并在其析构函数中关闭它。

每次需要使用数据库时,我都想过打开/关闭数据库,但我不能说这是否是一个好的解决方案。

甚至添加:

if(query.exec())
                {
                    query.clear();
                    db.commit();
                    return true;
                }

没有帮助。

客户端有:QVector&lt;Service*&gt; availableServices;QComboBox *servicesComboBox;,在客户端登录时检查所有可用服务:

void ClientTab::updateAllServices()
{
    availableServices.clear();
    availableServices = db->selectAllServices();

    servicesComboBox->clear();
    for(int i=0; i<availableServices.size(); i++)
        servicesComboBox->addItem(availableServices[i]->getServiceName(), QVariant::fromValue(availableServices[i]));

    servicesComboBox->setCurrentIndex(-1);
}

Service类:

#ifndef SERVICE_H
#define SERVICE_H

#include <QString>
#include <QMetaType>
#include <QVariant>

class Service : public QObject
{

   Q_OBJECT

public:
    Service(int id, QString name, double price);
    Service(){ id = -1; name = ""; price = 0;}

    QString getServiceName() const;
    void setServiceName(const QString &value);

    double getServicePrice() const;
    void setServicePrice(double value);

    int getId() const;
    void setId(int value);

private:

    QString name;
    double price;
    int id;
};

Q_DECLARE_METATYPE(Service*)

#endif // SERVICE_H

最后,从数据库中选择所有服务(我使用此方法填充 ClientTab 上的组合框):

QVector<Service*> DataBase::selectAllServices()
{
    QVector<Service*> services;

    if(!db.isOpen())
    {
        return services;
    }
    else
    {
        QSqlQuery query;
        if(query.exec("SELECT * FROM SERVICE;"))
        {
            while( query.next() )
            {
                int id = query.value(0).toInt();
                QString name = query.value(1).toString();
                double price = query.value(2).toDouble();

                Service *s = new Service(id, name, price);
                services.push_back(s);
            }
        }
        else
        {
            qDebug() << "DataBase::selectAllServices " << query.lastError();
        }
    }

    return services;
}

【问题讨论】:

  • 您是否尝试过在插入之前调用db.transaction() 并在之后调用db.commit()
  • @GiedriusD:我还没有,请稍等,我会做的。 编辑:不,也没有效果
  • 能否展示客户端登录后检查新服务的代码?
  • @GiedriusD:当然,我修改了我的问题。

标签: c++ database qt sqlite qsqldatabase


【解决方案1】:

你能仔细检查一下吗

void ClientTab::updateAllServices()

在每次客户端登录时调用(不仅在应用程序启动时)?

SQLite 数据库默认开启自动提交功能,因此您不需要提交任何内容或使用任何事务来完成这个简单的事情。

你能看到在 sqlite 命令行中使用 select * from service 添加的新服务吗?如果是这样,那么添加服务效果很好,您需要检查何时调用 updateAllServices()。

【讨论】:

    【解决方案2】:

    如果我正确理解您的问题,它是关于如何同步数据库的多个视图。这确实是一项艰巨的任务。

    如果在任何给定时间只有一个视图可见(就像在您的情况下似乎使用不同的选项卡一样),只需从数据库中重新加载数据并重新填充选项卡。你会怎么做?将信号contentChanged() 添加到您的主窗口,并让所有视图在看到数据时重新加载数据。 (或者当用户切换到特定选项卡时清除他们的数据并重新加载。)


    如果速度太慢或者您可以同时在多个视图中看到相同的内容:您应该使用 Qt 提供的模型,例如QListView + QAbstractListModel 而不是 QListWidget。如果你使用这些,同步是免费的,但你不应该再直接访问你的 SQL 数据库,而只能通过模型​​来改变它。

    【讨论】:

      猜你喜欢
      • 2020-06-18
      • 2019-01-04
      • 2016-01-10
      • 2023-03-18
      • 2012-11-23
      • 2010-09-26
      • 2013-12-20
      • 2012-01-08
      相关资源
      最近更新 更多