QT通过数据模型 *** 作数据库中的数据

QT通过数据模型 *** 作数据库中的数据,第1张

目录

数据信息类

数据库访问对象

数据库管理类

数据模型

搭建UI显示


在生活中做很多事情是有固定套路的,程序开发也一样。这里我介绍一下QT程序开发过程中数据库 *** 作搭配QT数据模型的常见用法,希望对你有帮助。虽然说QT提供了一些傻瓜数据模型比如QSqlTableModel、QSqlQueryModel等,方便开发者快速 *** 作和编辑数据库数据。但这些模型都有一个缺点,就是灵活性太差,如果我们需要做一个灵活性要求很高的产品项目的话,不建议使用这些数据模型。这里介绍一下自己将自定义数据模型和数据库 *** 作组合起来的一些经验,供大家参考,如果有什么不足的话,希望大家多提宝贵意见。

测试用例中我以一个消费者个人信息表为例进行说明。消费者信息表包含所有消费者的个人信息,包括:姓名、年龄、性别、身份z号。

数据信息类

首先我们定义消费者信息类,用来存储每一个消费者的个人信息,定义如下:

//customer.h
#ifndef CUSTOMER_H
#define CUSTOMER_H
#include 

//消费者信息类
//用来记录消费者的个人信息
class Customer
{
public:
    explicit Customer(const QString& name = "");

    int age() const;
    void setAge(int age);

    QString gender() const;
    void setGender(const QString &gender);

    QString iDNumber() const;
    void setIDNumber(const QString &iDNumber);

    int id() const;
    void setId(int id);

    QString name() const;
    void setName(const QString &name);

private:
    int mId;          //消费者的ID
    QString mName;    //消费者的姓名
    int mAge;         //消费者的年龄
    QString mGender;  //性别
    QString mIDNumber;//身份z号
};

#endif // CUSTOMER_H
//customer.cpp
#include "customer.h"
Customer::Customer(const QString &name):mId(-1),mName(name)
{}
int Customer::age() const
{
    return mAge;
}

void Customer::setAge(int age)
{
    mAge = age;
}

QString Customer::gender() const
{
    return mGender;
}

void Customer::setGender(const QString &gender)
{
    mGender = gender;
}

QString Customer::iDNumber() const
{
    return mIDNumber;
}

void Customer::setIDNumber(const QString &iDNumber)
{
    mIDNumber = iDNumber;
}

int Customer::id() const
{
    return mId;
}

void Customer::setId(int id)
{
    mId = id;
}

QString Customer::name() const
{
    return mName;
}
void Customer::setName(const QString &name)
{
    mName = name;
}
数据库访问对象

接下来我们定义数据库访问对象(DAO)用来访问数据库中消费者信息表中的内容,对应的实现如下:

//customerdao.h
#ifndef CUSTOMERDAO_H
#define CUSTOMERDAO_H

#include 
#include 

class QSqlDatabase;
class Customer;
//消费者数据表的访问对象
class CustomerDao
{
public:
    CustomerDao(QSqlDatabase& database);
    void init() const;

    //消费者信息的增删改查
    //添加一个新的消费者信息
    void addCustomer(Customer& customer) const;

    //更新某个消费者的个人信息
    void updateCustomer(const Customer& customer) const;

    //依据ID删除某个用户信息
    void removeCustomer(int id) const;

    //获取所有的消费者信息
    std::unique_ptr>> customers() const;

private:
    QSqlDatabase& mDatabase; //数据库 *** 作对象
};

#endif // CUSTOMERDAO_H

 

//customerdao.cpp
#include "customerdao.h"
#include "customer.h"
#include "DatabaseManager.h"

#include 
#include 
#include 

using namespace  std;

//初始化的时候将数据库 *** 作对象传递进来
CustomerDao::CustomerDao(QSqlDatabase &database):mDatabase(database)
{
}
void CustomerDao::init() const
{
    //如果对应的表不存在则创建一个新表  ID作为主键
    if (!mDatabase.tables().contains("customers")) {
        QSqlQuery query(mDatabase);
        query.exec("CREATE TABLE customers (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, "
                   "age INTEGER, gender TEXT, idNumber TEXT)");

        //校验一下SQL语法有没有错误
        DatabaseManager::debugQuery(query);
    }
}

void CustomerDao::addCustomer(Customer &customer) const
{
    //为了防止SQL注入,使用绑定的方式编写sql语句
    QSqlQuery query(mDatabase);
    query.prepare(QString("INSERT INTO customers")
        + " (name, age, gender, idNumber)"
        + " VALUES ("
        + ":name, "
        + ":age, "
          ":gender, "
          ":idNumber"
        + ")");
    query.bindValue(":name", customer.name());
    query.bindValue(":age",customer.age());
    query.bindValue(":gender",customer.gender());
    query.bindValue(":idNumber",customer.iDNumber());

    query.exec();
    customer.setId(query.lastInsertId().toInt());

    //验证SQL语句的正确性
    DatabaseManager::debugQuery(query);
}

//根据ID更新某个消费者的用户信息
void CustomerDao::updateCustomer(const Customer &customer) const
{
    QSqlQuery query(mDatabase);
    query.prepare(QString("UPDATE customers SET "
                          "name = (:name), "
                          "age = (:age), "
                          "gender = (:gender), "
                          "idNumber = (:idNumber) "
                          "WHERE id = (:id)"));
    query.bindValue(":id", customer.id());
    query.bindValue(":name", customer.name());
    query.bindValue(":age",customer.age());
    query.bindValue(":gender",customer.gender());
    query.bindValue(":idNumber",customer.iDNumber());
    query.exec();
    DatabaseManager::debugQuery(query);
}

void CustomerDao::removeCustomer(int id) const
{
    //依据ID删除某个用户的信息
    QSqlQuery query(mDatabase);
    query.prepare("DELETE FROM customers WHERE id = (:id)");
    query.bindValue(":id", id);
    query.exec();
    DatabaseManager::debugQuery(query);
}

std::unique_ptr > > CustomerDao::customers() const
{
    QSqlQuery query("SELECT * FROM customers", mDatabase);
    query.exec();
    unique_ptr>> list(new vector>());
    while(query.next()) {
        unique_ptr customer(new Customer());
        customer->setId(query.value("id").toInt());
        customer->setName(query.value("name").toString());
        customer->setAge(query.value("age").toInt());

        customer->setGender(query.value("gender").toString());
        customer->setIDNumber(query.value("idNumber").toString());
        list->push_back(move(customer));
    }
    return list;
}

所有的数据库访问 *** 作都在对应的数据库访问对象中进行实现,通过数据库访问对象我们就可以实现对对应的数据的增删改查了。

数据库管理类

每一个数据表都有一个对应的数据库访问对象,针对数据库本身和数据库访问对象我们也需要进行管理。这时候就引入一个数据库管理类了,它可以对数据库类型、数据库账号密码等内容进行管理,也可以对数据库访问对象进行管理,实现如下:

//DatabaseManager.h
#ifndef DATABASEMANAGER_H
#define DATABASEMANAGER_H

#include 
#include 
#include "customerdao.h"

class QSqlQuery;
class QSqlDatabase;

//数据库的名称
const QString DATABASE_FILENAME = "Database.db";

//数据库的管理者负责管理数据库的相关信息
class DatabaseManager
{
public:
    //对SQL语句的正确性进行校验
    static void debugQuery(const QSqlQuery& query);

    //数据库管理者的单例模式
    static DatabaseManager& instance();
    ~DatabaseManager();

protected:
    DatabaseManager(const QString& path = DATABASE_FILENAME);
    DatabaseManager& operator=(const DatabaseManager& rhs);

private:
    std::unique_ptr mDatabase;

public:
    const CustomerDao customerDao;
};
#endif // DATABASEMANAGER_H

 

//DatabaseManager.cpp
#include "DatabaseManager.h"
#include 
#include 
#include 
#include 
#include 
#include 

void DatabaseManager::debugQuery(const QSqlQuery& query)
{
    if (query.lastError().type() == QSqlError::ErrorType::NoError) {
        qDebug() << "Query OK:"  << query.lastQuery();
    } else {
       qWarning() << "Query KO:" << query.lastError().text();
       qWarning() << "Query text:" << query.lastQuery();
    }
}
DatabaseManager& DatabaseManager::instance()
{
    static DatabaseManager singleton;
    return singleton;
}

DatabaseManager::DatabaseManager(const QString& path) :
    mDatabase(new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE"))),
    customerDao(*mDatabase)
{
    //构造的时候打开数据库
    mDatabase->setDatabaseName(path);
    bool openStatus = mDatabase->open();
    qDebug() << "Database connection: " << (openStatus ? "OK" : "Error");
    customerDao.init();
}

DatabaseManager::~DatabaseManager()
{
    mDatabase->close();
}
数据模型

数据库 *** 作类完成之后,我们就可以实现数据模型和数据表信息字段的关联了。这里我们通过实现一个TableModel将数据库中的表内容以表格的形式显示出来。数据模型的实现如下:

//customermodel.h
#ifndef PICTUREMODEL_H
#define PICTUREMODEL_H

#include 
#include 
#include 
#include "DatabaseManager.h"
#include "customer.h"

class DatabaseManager;
class CustomerModel : public QAbstractTableModel
{
    Q_OBJECT
public:

    CustomerModel(QObject* parent = 0);
    //添加新消费者信息
    QModelIndex addCustomer(const Customer& customer);
    
    //行列数
    int rowCount(const QModelIndex& parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent) const;
    
    //设置和读取数据
    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
    bool setData(const QModelIndex& index, const QVariant& value, int role) override;
    
    //删除行
    Q_INVOKABLE bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
    QHash roleNames() const override;
    
    //设置表单元的属性
    Qt::ItemFlags flags(const QModelIndex &index) const;

private:
    bool isIndexValid(const QModelIndex& index) const;

private:
    DatabaseManager& mDb; //数据库管理类
    //数据库中的表内容
    std::unique_ptr>> mCustomers;
};

#endif // PICTUREMODEL_H

 

//customermodel.cpp
#include "CustomerModel.h"
#include "DatabaseManager.h"
#include "customerdao.h"

using namespace std;
CustomerModel::CustomerModel(QObject* parent) :
    QAbstractTableModel(parent),
    mDb(DatabaseManager::instance()),
    mCustomers(mDb.customerDao.customers())
{
}

QModelIndex CustomerModel::addCustomer(const Customer& customer)
{
    int rowIndex = rowCount();
    beginInsertRows(QModelIndex(), rowIndex, rowIndex);
    unique_ptr newCustomer(new Customer(customer));
    mDb.customerDao.addCustomer(*newCustomer);
    mCustomers->push_back(move(newCustomer));
    endInsertRows();
    return index(rowIndex, 0);
}

int CustomerModel::rowCount(const QModelIndex& parent) const
{
    Q_UNUSED(parent);
    return mCustomers->size();
}

int CustomerModel::columnCount(const QModelIndex &parent) const
{
    return 4;
}

QVariant CustomerModel::data(const QModelIndex& index, int role) const
{
    if (!isIndexValid(index)) {
        return QVariant();
    }

    if (role != Qt::DisplayRole && role != Qt::EditRole)
        return QVariant();

    const Customer& customer = *mCustomers->at(index.row());
    int column = index.column();
    if(column == 0)
    {
        return customer.name();
    }
    else if(column == 1)
    {
        return customer.age();
    }
    else if(column == 2)
    {
        return customer.gender();
    }
    else if(column == 3)
    {
        return customer.iDNumber();
    }
}

bool CustomerModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
    if (!isIndexValid(index)) {
        return false;
    }
    Customer& customer = *mCustomers->at(index.row());
    int column = index.column();
    if(column == 0)
    {
        customer.setName(value.toString());
    }
    else if(column == 1)
    {
        customer.setAge(value.toInt());
    }
    else if(column == 2)
    {
        customer.setGender(value.toString());
    }
    else if(column == 3)
    {
        customer.setIDNumber(value.toString());
    }
    mDb.customerDao.updateCustomer(customer);
    emit dataChanged(index, index);
    return true;
}

bool CustomerModel::removeRows(int row, int count, const QModelIndex& parent)
{
    if (row < 0
            || row >= rowCount()
            || count < 0
            || (row + count) > rowCount()) {
        return false;
    }
    beginRemoveRows(parent, row, row + count - 1);
    int countLeft = count;
    while (countLeft--) {
        const Customer& customer = *mCustomers->at(row + countLeft);
        mDb.customerDao.removeCustomer(customer.id());
    }
    mCustomers->erase(mCustomers->begin() + row,
                  mCustomers->begin() + row + count);
    endRemoveRows();
    return true;
}

QHash CustomerModel::roleNames() const
{
    QHash roles;
    roles[0] = "name";
    roles[1] = "age";
    roles[2] = "gender";
    roles[3] = "idNumber";
    return roles;
}

Qt::ItemFlags CustomerModel::flags(const QModelIndex &index) const
{
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
}

bool CustomerModel::isIndexValid(const QModelIndex& index) const
{
    if (index.row() < 0
            || index.row() >= rowCount()
            || !index.isValid()) {
        return false;
    }
    return true;
}

将数据库中的字段和模型绑定之后,我们就可以通过模型来 *** 作数据库中的信息了,非常方便吧。

下面我们搭建一个简单的UI来测试一下数据库信息的绑定。

搭建UI显示

UI显示效果如下,左边TableView显示数据表内容,右边按钮来动态的添加用户信息删除用户信息。

对应的实现逻辑如下: 

//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include "customermodel.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
public slots:
    //添加测试用户
    void slot_add_new_customer();

    //删除最后一个添加的用户
    void slot_delete_customer();

private:
    Ui::MainWindow *ui;
    CustomerModel* mCustomerModel;
};

#endif // MAINWINDOW_H
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "customermodel.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    mCustomerModel = new CustomerModel();
    ui->tableView->setModel(mCustomerModel);
    connect(ui->addCustomerBtn,SIGNAL(clicked(bool)),this,SLOT(slot_add_new_customer()));
    connect(ui->deleteCustomerBtn,SIGNAL(clicked(bool)),this,SLOT(slot_delete_customer()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

//添加测试用户
void MainWindow::slot_add_new_customer()
{
    Customer customer;
    customer.setAge(18);
    customer.setGender("女");
    customer.setName("小红");
    customer.setIDNumber("13031220201212009**");
    mCustomerModel->addCustomer(customer);
}

//删除最后一个添加的用户
void MainWindow::slot_delete_customer()
{
   int rowCount = mCustomerModel->rowCount();
   mCustomerModel->removeRows(rowCount-1,1);
}

 

如果感兴趣的,可以参考对应的源码,下载地址如下:

链接:https://pan.baidu.com/s/125SRIguWFnQHqlGnn71Scg

提取码:p1m8

 

 

 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1295184.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)

保存