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语句,容易出错,而且不便查看修改。所以多字段的表推荐这种操作方式。