Qt数据库之QSqlTableModel

我们熟知的qt数据库操作是使用QSqlDatabase和QSqlQuery。今天我来介绍一下使用QSqlTableModel来操作数据库的心得。

QSqlTableModel类为单个数据库表提供可编辑的数据模型。

QSqlTableModel是从单个表读取和写入数据库记录的高级接口。它构建在较低级别的QSqlQuery之上,可用于提供数据以查看QTableView等类。例如:

QSqlTableModel *model = new QSqlTableModel(parentObject, database);
    model->setTable("employee");
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->select();
    model->setHeaderData(0, Qt::Horizontal, tr("Name"));
    model->setHeaderData(1, Qt::Horizontal, tr("Salary"));

    QTableView *view = new QTableView;
    view->setModel(model);
    view->hideColumn(0); // don't show the ID
    view->show();

我们设置SQL表的名称和编辑策略,然后设置视图标题中显示的标签。编辑策略规定了用户在视图中所做的更改何时实际应用于数据库。可能的值是OnFieldChange,OnRowChange和OnManualSubmit。

QSqlTableModel也可用于以编程方式访问数据库,而不将其绑定到视图:

QSqlQueryModel model;
    model.setQuery("SELECT * FROM employee");
    int salary = model.record(4).value("salary").toInt();

上面的代码片段从雇员查询SELECT的结果集中的记录4中提取工资字段。

可以使用setFilter()设置过滤器,也可以使用setSort()修改排序顺序。 最后,你必须调用select()来用数据填充模型。

tablemodel示例说明如何使用QSqlTableModel作为QTableView的数据源。

QSqlTableModel不提供对外键的直接支持。 如果要解析外键,请使用QSqlRelationalTableModel和QSqlRelationalDelegate。

具体例子如下:

dbhelper.h

#ifndef DBHELPER_H
#define DBHELPER_H

#include <QObject>
#include <QSqlDatabase>
#include <QSqlRecord>
#include <QSqlTableModel>
#include <QSqlError>
#include <QMessageBox>
#include "library.h"

class DBHelper :public QObject
{

public:

    explicit DBHelper(QObject *parent = 0);
    ~DBHelper();

    void connectDB();

    bool modelIsNull();

    bool doTransaction();

    void getLibrary(Library* pLib);

    bool updateLibrary(LibraryRecord *pLibRec);

private:

    QSqlDatabase m_db;

    QSqlTableModel *m_pModel;

};

#endif // DBHELPER_H

dbhelper.cpp

#include "dbhelper.h"
#include <QDebug>

DBHelper::DBHelper(QObject *parent):QObject(parent)
{
    m_pModel = NULL;
    connectDB();
}

DBHelper::~DBHelper()
{
    if(m_pModel != NULL)
    {
        delete m_pModel;
    }

    if(m_db.isOpen())
    {
        m_db.close();
        qDebug()<<"Database is closed";
    }
}

void DBHelper::connectDB()
{
    m_db = QSqlDatabase::addDatabase("QODBC");
    m_db.setDatabaseName(QString("DRIVER={Microsoft Access Driver (*.mdb)};FIL={MS Access};DBQ=%1;PWD=succeeder.com.cn").arg(m_pPrefs->getStrDataFilePath()));
    bool m_ok = m_db.open();
    if(m_ok)
   {
        m_pModel = new QSqlTableModel(this,m_db);
        qDebug()<< "Database opened successfully";
    }
    else
    {
        qDebug()<< "Database failed to open";//处理
    }
}

bool DBHelper::modelIsNull()
{
    return (m_pModel == NULL);
}

bool DBHelper::doTransaction()
{
    m_db.transaction();//开始事务操作

    if(m_pModel->submitAll())
    {
        m_db.commit();//提交
        return true;
    }else
    {
        m_db.rollback();//回滚
        QMessageBox::warning(NULL,tr("tableModel"),tr("Database Error: %1").arg(m_pModel->lastError().text()));
        return false;
    }
}

void DBHelper::getLibrary(Library *pLib)
{
    m_pModel->setTable("Library");//设置表中的数据填充模型
    m_pModel->setEditStrategy(QSqlTableModel::OnManualSubmit);//所有更改都将缓存在模型中,直到调用submitAll()或revertAll()。
    m_pModel->select(); //显示结果
    int rowCount = m_pModel->rowCount();//获得表的行数

    if (rowCount > 0)
    {
        for(int i = 0;i < rowCount;i++)
        {
            QSqlRecord rec = m_pModel->record(i);//返回模型中行的记录。
            LibraryRecord *pLibRec = new LibraryRecord;
            pLibRec->m_nId         = rec.value("Library_id").toInt();//返回记录中位于索引处的字段的值。 如果索引超出范围,则返回无效的QVariant。
            pLibRec->m_strCode     = rec.value("Library_code").toString();
            pLibRec->m_strName     = rec.value("Library_name").toString();
            pLibRec->m_nType       = rec.value("Library_type").toInt();

            pLib->fillMap(pLibRec);
        }
    }
}

bool DBHelper::updateLibrary(LibraryRecord *pLibRec)
{
    m_pModel->setTable("Library");
    m_pModel->setFilter(QObject::tr("Library_id = %1").arg(pLibRec->m_nId));//将当前过滤器设置为过滤器。过滤器是一个没有关键字WHERE的SQL WHERE子句(例如,name ='Josephine')。

    m_pModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    m_pModel->select();

    int rowCount = m_pModel->rowCount();//获得表的行数
    QSqlRecord rec = m_pModel->record();
    rec.setGenerated("Library_id",false);//将名称为name的字段的生成标志设置为自动生成,通常用于自动编号处理。
    rec.setValue("Library_code",pLibRec->m_strCode);
    rec.setValue("Library_name",pLibRec->m_strName);
    rec.setValue("Library_type",pLibRec->m_nType);

    if(rowCount)
    {
        m_pModel->setRecord(0,rec);//更新纪录
    }else
    {
        m_pModel->insertRecord(-1,rec);//在结尾插入记录
    }

    return doTransaction();
}

此处连接的数据库是微软的ACCESS。

值得注意的是自动编号的处理,setGenerated完美的解决了这个问题。

这种操作数据库的方式避免了多字段的情况下的SQL语句,容易出错,而且不便查看修改。所以多字段的表推荐这种操作方式。