QT数据库SQLite:QSqlRelationalTableModel 类
关系数据库概念
例如下列departments、majors、studInfo 这 3 个数据表之间存在关系。
主键与外键
标记“**”的是主键字段,标记“*”的是外键字段。主键字段是一个数据表中表示记录唯一性的字段,例如 studInfo 数据表中的 studID 字段。外键字段是与其他数据表的主键存在关系的字段。
studInfo 数据表中的 departID 字段就是外键字段,它与 departments 数据表中的 departID 字段存在关系。studInfo 数据表中的 departID 存储的是编码,编码的含义需要查询departments 数据表中具有相同 departID 值的一条记录中的 department 字段才可知道。
编码与含义
studInfo 数据表中的 departID 和 majorID 字段一般称为编码字段,departments 数据表和 majors 数据表一般称为编码表。编码表的一条记录有编码字段和编码含义字段,例如 departments 数据表 中,departID 是编码字段,department 是编码含义字段。
在数据库设计中经常采用编码字段和编码表,一是可以减少数据表存储的数据量,例如在studInfo 数据表中不用存储每个学院的全名,而只需存储学院的编码;二是便于修改,例如如果某个学院的名称改变了,那么只需修改 departments 数据表中的一条记录。
主从关系
具有外键关联的两个数据表构成主从关系,主表中的一条记录关联从表中的多条记录。例如, departments 数据表是主表,studInfo 数据表是从表,通过 departments 数据表中一条记录的departID值可以查询出 studInfo 数据表中的多条记录。在删除departments表中的某个学院后,studInfo 表中隶属于该学院的记录也将会被删除。这种方式更新、修改删除都比较方便。
QSqlRelationalTableModel介绍
QSqlRelationalTableModel 是 QSqlTableModel 的子类,它可以作为关系数据表的模型类。
创建对象和设置数据表
QSqlRelationalTableModel 只有一种构造函数,其函数原型定义如下:
QSqlRelationalTableModel(QObject *parent = nullptr, const QSqlDatabase &db=QSqlDatabase())
在创建 QSqlRelationalTableModel 对象时,如果不指定参数 db 的值,就使用应用程序默认的
数据库连接。
创建数据库连接后,用函数 setTable()设置数据表:
tabModel= new QSqlRelationalTableModel(this);
tabModel->setTable("studInfo"); //设置数据表
设置外键关系
关键函数是 setRelation(),该函数原型定义如下:
void QSqlRelationalTableModel::setRelation(int column, const QSqlRelation &relation)
其中,参数 column 是外键字段的字段序号,例如 studInfo 数据表中 departID 字段的序号是 3;参 数 relation 是一个 QSqlRelation 类型的变量,用于表示外键字段关联的编码表、编码字段、编含义字段等信息。
QSqlRelation 类的构造函数原型定义如下:
QSqlRelation(const QString &tableName, const QString &indexColumn, const QString &displayColumn)
其中,tableName 是编码表名称,indexColumn 是外键字段名称,displayColumn 是编码表中代码含义字段的名称。
当使用函数 setRelation()为一个外键字段设置关系时,QSqlRelationalTableModel 内部实际上会创建一个 QSqlTableModel 对象作为编码表的数据模型。
示例程序解读
设置数据表关系
在打开数据表时,创建一个QSqlRelationalTableModel并连接到DB数据库,设置模型的数据表为studInfo,编辑策略为OnManualSubmit(需要手动调用submitAll来更新到数据库)。
void MainWindow::on_actOpenDB_triggered()
{
QString aFile=QFileDialog::getOpenFileName(this,"选择文件","","SQLite数据库(*.db3)");
if (aFile.isEmpty())
return;
//打开数据库
DB=QSqlDatabase::addDatabase("QSQLITE"); //添加SQLITE数据库驱动
DB.setDatabaseName(aFile); //设置数据库名称
// DB.setHostName();
// DB.setUserName();
// DB.setPassword();
if (DB.open())
openTable(); //打开数据表
else
QMessageBox::warning(this, "错误", "打开数据库失败");
}
//打开数据表
void MainWindow::openTable()
{
tabModel=new QSqlRelationalTableModel(this,DB);
tabModel->setTable("studInfo"); //设置数据表
tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit); //编辑策略
tabModel->setSort(tabModel->fieldIndex("studID"),Qt::AscendingOrder);
selModel=new QItemSelectionModel(tabModel,this); //创建选择模型
connect(selModel,&QItemSelectionModel::currentChanged,this, &MainWindow::do_currentChanged);
// connect(selModel,SIGNAL(currentChanged(QModelIndex,QModelIndex)),
// this,SLOT(do_currentChanged(QModelIndex,QModelIndex)));
ui->tableView->setModel(tabModel);
ui->tableView->setSelectionModel(selModel);
tabModel->setHeaderData(tabModel->fieldIndex("studID"), Qt::Horizontal, "学号");
tabModel->setHeaderData(tabModel->fieldIndex("name"), Qt::Horizontal, "姓名");
tabModel->setHeaderData(tabModel->fieldIndex("gender"), Qt::Horizontal, "性别");
tabModel->setHeaderData(tabModel->fieldIndex("departID"),Qt::Horizontal, "学院");
tabModel->setHeaderData(tabModel->fieldIndex("majorID"), Qt::Horizontal, "专业");
//设置代码字段的关系
tabModel->setRelation(tabModel->fieldIndex("departID"),
QSqlRelation("departments","departID","department")); //学院
tabModel->setRelation(tabModel->fieldIndex("majorID"),
QSqlRelation("majors","majorID","major")); //专业
ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView)); //为关系型字段设置默认代理组件
// ui->tableView->setItemDelegateForColumn(tabModel->fieldIndex("departID"),
// new QSqlRelationalDelegate(ui->tableView)); //为关系型字段设置缺省代理组件
// ui->tableView->setItemDelegateForColumn(tabModel->fieldIndex("majorID"),
// new QSqlRelationalDelegate(ui->tableView)); //为关系型字段设置缺省代理组件
tabModel->select(); //查询数据表的数据
ui->actOpenDB->setEnabled(false);
ui->actRecAppend->setEnabled(true);
ui->actRecInsert->setEnabled(true);
ui->actRecDelete->setEnabled(true);
ui->actFields->setEnabled(true);
}
示例代码中,有两个点比较关键
1、设置外键字段的关系
tabModel->setRelation(tabModel->fieldIndex("departID"),QSqlRelation("departments","departID","department")); //学院
tabModel->setRelation(tabModel->fieldIndex("majorID"),QSqlRelation("majors","majorID","major")); //专业
将studInfo数据表中departID外键字段设置为另一个编码表departments对应的字段,并设置字段的含义为编码表中department字段。这样在显示studInfo表中departID时,会自动映射到departments编码表中的department字段。
2、设置代理组件
ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView));
设置后,假设在 tableView 中编辑“学院”和“专业”两个字段的数据时,就会出现一个下拉列表框,
下拉列表内容就是编码表中编码含义字段的所有记录的数据。
添加插入删除记录
这个不用多讲,可查看往期博客
void MainWindow::on_actRecAppend_triggered()
{//添加记录
tabModel->insertRow(tabModel->rowCount(),QModelIndex()); //在末尾添加一行
QModelIndex curIndex=tabModel->index(tabModel->rowCount()-1,1);
selModel->clearSelection(); //清空选择项
selModel->setCurrentIndex(curIndex,QItemSelectionModel::Select); //设置当前行
}
void MainWindow::on_actRecInsert_triggered()
{//插入记录
QModelIndex curIndex=ui->tableView->currentIndex(); //当前行的模型索引
tabModel->insertRow(curIndex.row(),QModelIndex());
selModel->clearSelection();
selModel->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}
void MainWindow::on_actRecDelete_triggered()
{//删除当前行
tabModel->removeRow(selModel->currentIndex().row());
tabModel->submitAll(); //立即提交修改
}
保存和取消
在打开连接数据库后,设置的OnManualSubmit,因此界面的改变想要更新到数据库,需要手动调用submitAll()或者revertAll()来保存或撤销。submitAll()将界面的更改更新到数据库中,revertAll()将界面的更改撤销,也就是重新读取之前数据库中的数据还原界面组件的显示。
void MainWindow::on_actSubmit_triggered()
{//保存修改
bool res=tabModel->submitAll();
if (!res)
QMessageBox::information(this, "消息", "数据保存错误,错误信息\n"
+tabModel->lastError().text());
else
{
ui->actSubmit->setEnabled(false);
ui->actRevert->setEnabled(false);
}
}
void MainWindow::on_actRevert_triggered()
{//取消修改
tabModel->revertAll();
ui->actSubmit->setEnabled(false);
ui->actRevert->setEnabled(false);
}
原文地址:https://blog.csdn.net/qq_46144191/article/details/144400515
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!