找回密码
 立即注册
收起左侧

第26篇 数据库(六)SQL关系表格模型QSqlRelationalTableModel

37
回复
24695
查看
[复制链接]
累计签到:1206 天
连续签到:1 天
来源: 2013-5-21 20:54:13 显示全部楼层 |阅读模式
SQL关系表格模型QSqlRelationalTableModel

版权声明

该文章原创于Qter开源社区(www.qter.org),作者yafeilinux,转载请注明出处!


导语

       QSqlRelationalTableModel继承自QSqlTableModel,并且对其进行了扩展,提供了对外键的支持。一个外键就是一个表中的一个属性和其他表中的主键属性之间的一对一的映射。例如,student表中的course属性对应的是course表中的id属性,那么就称属性course是一个外键。因为这里的course属性的值是一些数字,这样的显示很不友好,使用关系表格模型,就可以将它显示为course表中的name属性的值。


环境:Windows Xp + Qt 4.8.4+QtCreator 2.6.2


目录

一、使用外键
二、使用委托


正文


一、使用外键

1.新建Qt Gui应用,名称为relationalTableModel,基类为QMainWindow,类名为MainWindow。完成后打开relationalTableModel.pro项目文件,将第一行改为:
QT       += coregui sql
       然后保存该文件。

2.下面向项目中添加新的C++头文件connection.h,并更改其内容如下:
#ifndef CONNECTION_H
#define CONNECTION_H
#include <QSqlDatabase>
#include <QSqlQuery>
static bool createConnection()
{
   QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
   db.setDatabaseName("database.db");
   if(!db.open()) return false;
   QSqlQuery query;
   query.exec("create table student (id int primary key, name vchar,course int)");
   query.exec("insert into student values(1,'yafei0',1)");
   query.exec("insert into student values(2,'yafei1',1)");
   query.exec("insert into student values(3,'yafei2',2)");
   
query.exec("create table course (id int primarykey, name vchar, teacher vchar)");
   query.exec("insert into course values(1,'Math','yafeilinux1')");
   query.exec("insert into course values(2,'English','yafeilinux2')");
   query.exec("insert into course values(3,'Computer','yafeilinux3')");
   return true;
}
#endif // CONNECTION_H

       在这里建立了两个表,student表中有一项是course,它是int型的,而course表的主键也是int型的。如果要将course项和course表进行关联,它们的类型就必须相同,一定要注意这一点。

3.更改main.cpp文件内容如下:
#include "mainwindow.h"
#include <QApplication>
#include "connection.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    if(!createConnection()) return 1;
    MainWindow w;
    w.show();
   
    return a.exec();
}


4.然后到mainwindow.h文件中,先包含头文件:
#include<QSqlRelationalTableModel>
然后添加private类型对象声明:
QSqlRelationalTableModel *model;


5.到设计模式,往界面上拖放一个Table View部件。


6.mainwindow.cpp文件中,在构造函数里添加如下代码:
model = new QSqlRelationalTableModel(this);
//属性变化时写入数据库
model->setEditStrategy(QSqlTableModel::OnFieldChange);
model->setTable("student");
//将student表的第三个属性设为course表的id属性的外键,
//并将其显示为course表的name属性的值
model->setRelation(2,QSqlRelation("course","id","name"));
model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));
model->setHeaderData(2, Qt::Horizontal, QObject::tr("Course"));
model->select();
ui->tableView->setModel(model);

       这里修改了model的提交策略,OnFieldChange表示只要属性被改动就马上写入数据库,这样就不需要我们再执行提交函数了。setRelation()函数实现了创建外键,注意它的格式就行了。


7.运行程序,效果如下图所示。



       可以看到Course属性已经不再是编号,而是具体的课程了。关于外键,大家也应该有一定的认识了吧,说简单点就是将两个相关的表建立一个桥梁,让它们关联起来。


二、使用委托

       有时我们也希望,如果用户更改课程属性,那么只能在课程表中有的课程中进行选择,而不能随意填写课程。Qt中还提供了一个QSqlRelationalDelegate委托类,它可以为QSqlRelationalTableModel显示和编辑数据。这个委托为一个外键提供了一个QComboBox部件来显示所有可选的数据,这样就显得更加人性化了。使用这个委托是很简单的,我们先在mainwindow.cpp文件中添加头文件#include <QSqlRelationalDelegate>,然后继续在构造函数中添加如下一行代码:
ui->tableView->setItemDelegate(
                new QSqlRelationalDelegate(ui->tableView));

       运行程序,效果如下图所示。


结语

       我们可以根据自己的需要来选择使用哪个模型。如果熟悉SQL语法,又不需要将所有的数据都显示出来,那么只需要使用QSqlQuery就可以了。对于QSqlTableModel,它主要是用来显示一个单独的表格的,而QSqlQueryModel可以用来显示任意一个结果集,如果想显示任意一个结果集,而且想使其可读写,那么建议子类化QSqlQueryModel,然后重新实现flags()setData()函数。更多相关内容请查看《Qt Creator快速入门》17章。



涉及到的源码下载:



上一篇:第25篇 数据库(五)SQL表格模型QSqlTableModel

下一篇: 第27篇 XML(一)使用DOM读取XML文档

返回:系列教程目录   


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

尚未签到

2013-11-5 20:06:34 显示全部楼层
你好,我想请教一下:model->setRelation(2,QSqlRelation("course","id","name"));这句会使得显示出来的student表里的学生ID被替换为name,有没有办法让它不要替换,也就是说学生ID跟对应的name一起显示出来?谢谢
回复 支持 1 反对 0

使用道具 举报

尚未签到

2013-7-31 08:58:02 显示全部楼层
{:soso_e179:}{:soso_e179:}{:soso_e179:}v{:soso_e179:}
回复 支持 反对

使用道具 举报

累计签到:4 天
连续签到:1 天
2013-8-20 10:52:48 显示全部楼层
楼主 最后一个使用委托。
然后修改被委托的列,展示的值显示id,不会被name替代,这个怎么搞。重新设置外键关联查询一遍都不行  - -#
回复 支持 反对

使用道具 举报

累计签到:1206 天
连续签到:1 天
2013-8-20 12:29:32 显示全部楼层
TigerQter 发表于 2013-8-20 10:52
楼主 最后一个使用委托。
然后修改被委托的列,展示的值显示id,不会被name替代,这个怎么搞。重新设置外键 ...

下载源码试试是否可以
回复 支持 反对

使用道具 举报

累计签到:1206 天
连续签到:1 天
2013-11-6 18:32:51 显示全部楼层
XXian 发表于 2013-11-5 20:06
你好,我想请教一下:model->setRelation(2,QSqlRelation("course","id","name"));这句会使得显示出来的stu ...

你的意思是说,以前只显示id,现在想id和name都显示吗?
回复 支持 反对

使用道具 举报

尚未签到

2013-11-6 19:03:57 显示全部楼层
yafeilinux 发表于 2013-11-6 18:32
你的意思是说,以前只显示id,现在想id和name都显示吗?

写错了,应该是student里原来课程的ID因为model->setRelation(2,QSqlRelation("course","id","name"));这句被替换为课程的name了,我希望能让课程的ID和课程的name都能显示出来,而不要被替换掉

点评

实现了没?我也有这个疑问?  详情 回复 发表于 2017-5-16 08:16
回复 支持 反对

使用道具 举报

累计签到:1206 天
连续签到:1 天
2013-11-12 09:15:30 显示全部楼层
XXian 发表于 2013-11-6 19:03
写错了,应该是student里原来课程的ID因为model->setRelation(2,QSqlRelation("course","id","name"));这 ...

这个使用这种方法应该不好实现,可以考虑修改表的内容。
回复 支持 反对

使用道具 举报

尚未签到

2014-7-7 10:52:49 显示全部楼层
老师,我原来用QSqlTableModel可以修改行,用了QSqlRelationalTableModel后就无法修改了,只能新建,删除也不行,求指导
回复 支持 反对

使用道具 举报

尚未签到

2014-7-7 10:54:03 显示全部楼层
另外用的是OnManualSubmit策略
回复 支持 反对

使用道具 举报

累计签到:1206 天
连续签到:1 天
2014-7-7 22:43:44 显示全部楼层
天降苹果糖 发表于 2014-7-7 10:54
另外用的是OnManualSubmit策略

可以啊。直接使用removeRow()
回复 支持 反对

使用道具 举报

累计签到:255 天
连续签到:1 天
2015-5-7 13:24:39 显示全部楼层
老师 问一下
//属性变化时写入数据库
model->setEditStrategy(QSqlTableModel::OnFieldChange);
这个是将student的course改变么
还是这个程序只是在Table里面显示出来是2个表的联合内容  但是数据库表内容没改变
回复 支持 反对

使用道具 举报

累计签到:255 天
连续签到:1 天
2015-5-7 13:26:25 显示全部楼层
yafeilinux 发表于 2014-7-7 22:43
可以啊。直接使用removeRow()

如果我要1个表关联几个表 也是一样的做法么
回复 支持 反对

使用道具 举报

累计签到:109 天
连续签到:1 天
2016-1-22 09:12:27 显示全部楼层
本帖最后由 silverdemon 于 2016-1-22 09:13 编辑

我也出现一楼说的情况:
最后一个使用委托。
然后修改被委托的列,展示的值显示id,不会被name替代,这个怎么搞。重新设置外键关联查询一遍都不行

更改course之后,显示的是ID值,而不是course的name

环境:win10 + Qt 5.5.1 (mingw)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 支持 反对

使用道具 举报

累计签到:1206 天
连续签到:1 天
2016-1-25 17:08:42 显示全部楼层
z55716368 发表于 2015-5-7 13:24
老师 问一下
//属性变化时写入数据库
model->setEditStrategy(QSqlTableModel::OnFieldChange);

应该是直接写入数据库,可以自己测试下。
回复 支持 反对

使用道具 举报

累计签到:10 天
连续签到:1 天
2016-3-5 17:20:06 显示全部楼层
老师我照着您的做法自己手打,然后又新建了一个直接拷贝网页代码,这两个得到的表每次打开会重复插入数据。而使用下载的代码得到的结果每次打开数据都不会重复插入。我仔细检查了代码一模一样。这是怎么回事啊?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 支持 反对

使用道具 举报

累计签到:1206 天
连续签到:1 天
2016-3-6 11:18:59 显示全部楼层
太阳的冷漠 发表于 2016-3-5 17:20
老师我照着您的做法自己手打,然后又新建了一个直接拷贝网页代码,这两个得到的表每次打开会重复插入数据。 ...

先把目录里面生成的数据文件删除。
回复 支持 反对

使用道具 举报

累计签到:10 天
连续签到:1 天
2016-3-6 16:26:08 显示全部楼层
yafeilinux 发表于 2016-3-6 11:18
先把目录里面生成的数据文件删除。

可是删掉之后第一次打开没事,第二打开又重新插入了。而下载的代码不管删与不删都不会这样。这是怎么回事啊
回复 支持 反对

使用道具 举报

累计签到:1206 天
连续签到:1 天
2016-3-7 21:46:31 显示全部楼层
太阳的冷漠 发表于 2016-3-6 16:26
可是删掉之后第一次打开没事,第二打开又重新插入了。而下载的代码不管删与不删都不会这样。这是怎么回事 ...

你确定没有错吗?

query.exec("create table student (id int primarykey, name vchar,course int)");

这里的primary key中间应该有空格。

应该是发帖的时候那个空格不显示了。
回复 支持 反对

使用道具 举报

累计签到:18 天
连续签到:1 天
2016-3-18 22:37:20 显示全部楼层
好好学习一下了,一直想写个数据库方面的小程序
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册