У меня есть простое приложение, где я могу входить / выходить из пользователей. Когда пользователь входит в систему, приложение отображает соответствующую вкладку в главном окне (сотрудник / администратор / клиент). у меня есть 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<Service*> 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;
}
Не могли бы вы проверить
void ClientTab::updateAllServices()
вызывается каждый раз, когда клиент входит в систему (не только при запуске приложения)?
В базе данных SQLite по умолчанию включен автокоммит, поэтому вам не нужно ничего фиксировать или использовать любую транзакцию для этой простой вещи.
Вы видите новый сервис, добавленный в командной строке sqlite с помощью select * from service? Если это так, то добавление службы работает хорошо, и вам нужно проверить, когда вы вызываете updateAllServices ().
Если я правильно понимаю вашу проблему, речь идет о том, как синхронизировать несколько представлений базы данных. Это действительно сложная задача.
Если в любой момент времени видно только одно из представлений (как, по-видимому, в вашем случае будет с разными вкладками), просто перезагрузите данные из базы данных и заново заполняйте вкладки. Как бы вы это сделали? Добавить сигнал contentChanged()
в главное окно, и пусть все представления перезагрузят данные, когда они их увидят. (Или очистите их данные и перезагрузите, когда пользователь переключится на конкретную вкладку.)
Если это слишком медленно или вы можете видеть один и тот же контент в нескольких представлениях одновременно: вы должны использовать модели, предоставленные Qt, например, QListView + QAbstractListModel
вместо QListWidget
, Если вы используете их, синхронизация бесплатна, но вам больше не нужно обращаться к базе данных SQL напрямую, а изменять ее только через модель.