【Qt之QSqlRelationalTableModel】描述及使用

描述

QSqlRelationalDelegate链接: https://blog.csdn.net/MrHHHHHH/article/details/134690139

QSqlRelationalTableModel类为单个数据库表提供了一个可编辑的数据模型,并支持外键。
QSqlRelationalTableModel的行为类似于QSqlTableModel,但允许将列设置为其他数据库表的外键。

左边的屏幕截图显示了QTableView中一个普通的QSqlTableModel。外键(城市和国家)不能解析为人类可读的值。

右边的屏幕截图显示了一个QSqlRelationalTableModel,外键被解析为人类可读的文本字符串。

下面的代码片段展示了如何建立QSqlRelationalTableModel:

cpp 复制代码
	  model->setTable("employee");
      model->setRelation(2, QSqlRelation("city", "id", "name"));
      model->setRelation(3, QSqlRelation("country", "id", "name"));

setRelation()函数调用在两个表之间建立关系。第一个调用指定表employee中的第2列是一个外键,它映射表city的字段id,并且视图应该向用户显示城市的名称字段。第二个调用对列3执行类似的操作。

如果使用读写的QSqlRelationalTableModel,可能希望在视图上使用QSqlRelationalDelegate。与默认委托不同,QSqlRelationalDelegate为作为其他表的外键的字段提供了一个组合框。要使用该类,只需在带有QSqlRelationalDelegate实例的视图上调用QAbstractItemView::setItemDelegate():

cpp 复制代码
	  QTableView *view = new QTableView;
      view->setModel(model);
      view->setItemDelegate(new QSqlRelationalDelegate(view));

relationaltablemodel示例演示了如何将QSqlRelationalTableModelQSqlRelationalDelegate结合使用,为表提供外键支持。

注意:

  • 表必须声明主键。
  • 表的主键可能不包含对另一个表的关系。
  • 如果关系表包含引用引用表中不存在的行的键,则包含无效键的行将不通过模型公开。用户或数据库有责任维护引用完整性。
  • 如果关系的显示列名称也用作关系表中的列名称,或者如果它在多个关系中用作显示列名称,则会被别名。别名是关系的表名、显示列名和一个唯一的id,用下划线连接(例如tablename_columnname_id)。QSqlRecord::fieldName()将返回别名列名。当检测到重复时,所有重复显示列名的出现都会被别名,但不会对主表中的列名进行任何别名操作。别名对QSqlRelation没有影响,因此QSqlRelation::displayColumn()将返回原始显示列名。
  • 参考表名称被别名。别名是单词"relTblAl"和关联的列索引用下划线连接(例如,relTblAl_2)。别名可用于过滤表(例如,setFilter("relTblAl_2='Oslo' OR relTblAl_3='USA'"))。
  • 使用setData()时,角色应始终为Qt::EditRole,使用data()时,角色应始终为Qt::DisplayRole

常用方法

  1. 枚举:enum JoinMode
常量 描述 解释
QSqlRelationalTableModel::InnerJoin 0 - Inner join mode, return rows when there is at least one match in both tables. --- 内部连接模式,当两个表中至少有一个匹配时返回行。
QSqlRelationalTableModel::InnerJoin 1 - Left join mode, returns all rows from the left table (table_name1), even if there are no matches in the right table (table_name2). --- 左连接模式,返回左表(table_name1)中的所有行,即使右表(table_name2)中没有匹配。
  1. void setJoinMode(QSqlRelationalTableModel::JoinMode joinMode)

设置SQL joinMode以显示或隐藏外键为NULL的行。在InnerJoin模式(默认)中,这些行将不会显示:如果想显示它们,请使用LeftJoin模式。

  1. QSqlRelation relation(int column) const

返回列的关系,如果没有设置关系,则返回无效关系。

  1. QSqlTableModel* relationModel(int column) const

返回一个QSqlTableModel对象,用于访问列为外键的表,如果给定列没有关系,则返回0。

返回的对象归QSqlRelationalTableModel所有。

  1. void setRelation(int column, const QSqlRelation &relation)

让指定的列是由关系指定的外索引。

Ex:

cpp 复制代码
    model->setTable("employee");
    model->setRelation(2, QSqlRelation("city", "id", "name"));

setRelation()调用指定employee表中的第2列是一个外键,它映射表city的字段id,并且视图应该向用户显示城市的名称字段。

注意:表的主键不能包含与另一个表的关系。

  1. void clear()

重新实现QSqlQueryModel::clear()方法。用于清除模型数据。

  1. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const

为索引引用的项返回存储在给定角色下的数据。

注意:如果没有要返回的值,则返回无效的QVariant,而不是返回0`。

  1. bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex())

在支持此功能的模型上,从模型中删除从parent下给定列开始的计数列。

如果列已成功删除,则返回true;否则返回false。

基类实现不做任何事情并返回false。

如果实现了自己的模型,如果希望支持删除,则可以重新实现此函数。或者,可以提供自己的API来修改数据。

  1. bool select()

使用通过setTable()设置的表中的数据填充模型,使用指定的筛选和排序条件,如果成功则返回true;否则返回false。

注意:调用select()将恢复所有未提交的更改并删除所有插入的列。

  1. bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)

QAbstractItemModel::setData()重新实现。

将具有指定索引的项中角色的数据设置为给定的值。根据编辑策略的不同,值可以立即应用于数据库,也可以缓存在模型中。

如果值可以设置,则返回true,如果出现错误(例如,如果索引超出边界)则返回false。

对于关系列,value必须是索引,而不是显示值。索引也必须存在于被引用的表中,否则函数返回false。

示例

.pro中添加QT += sql

包含头文件

cpp 复制代码
#include <QtWidgets>
#include <QtSql>

#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
  1. // 创建表及插入数据
cpp 复制代码
static bool createConnection()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    // 创建在内存中
    db.setDatabaseName(":memory:");
    if (!db.open()) {
        QMessageBox::critical(0, qApp->tr("Cannot open database"),
            qApp->tr("Unable to establish a database connection.\n"
                     "This example needs SQLite support. Please read "
                     "the Qt SQL driver documentation for information how "
                     "to build it.\n\n"
                     "Click Cancel to exit."), QMessageBox::Cancel);
        return false;
    }

    // 使用SqlQuery进行表创建及数据添加
    QSqlQuery query;
    query.exec("create table person (id int primary key, "
               "firstname text, lastname int)");
    query.exec("insert into person values(0, '0', 0)");
    query.exec("insert into person values(1, '1', 1)");
    query.exec("insert into person values(4, '2', 2)");
    query.exec("insert into person values(3, '3', 3)");

    query.exec("create table itemF (id int primary key,"
                                             "firstName varchar(20))");
    query.exec("insert into itemF "
               "values(0, '小明')");
    query.exec("insert into itemF "
               "values(2, '小华')");
    query.exec("insert into itemF "
               "values(3, '小芳')");
    query.exec("insert into itemF "
               "values(1, '小诸葛')");

    query.exec("create table itemL (id int, lastName varchar(20))");
    query.exec("insert into itemL values(0, '赵')");
    query.exec("insert into itemL values(1, '钱')");
    query.exec("insert into itemL values(2, '孙')");
    query.exec("insert into itemL values(3, '李')");

    return true;
}
  1. // 初始化模型
cpp 复制代码
void initializeModel(QSqlRelationalTableModel *model)
{
    // 设置表名
    model->setTable("person");
    // 手动提交
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    // 设置外键
    model->setRelation(1, QSqlRelation("itemF", "id", "firstName"));
    model->setRelation(2, QSqlRelation("itemL", "id", "lastName"));
    // 添加表头
    model->setHeaderData(0, Qt::Horizontal, QObject::tr("id"));
    model->setHeaderData(1, Qt::Horizontal, QObject::tr("firstName"));
    model->setHeaderData(2, Qt::Horizontal, QObject::tr("lastName"));
    // 刷新
    model->select();
}

上述代码:

  • 创建了一个名为 person 的表,并添加了一些数据。
  • 创建了两个名为 itemFitemL 的表,并添加了一些具有 idfirstNamelastName 属性的数据
  • 这些表和数据将用于后面的 QSqlRelationalTableModel 示例
  • 最后,该函数返回 true
  1. // 创建视图
cpp 复制代码
QTableView *createView(const QString &title, QSqlTableModel *model)
{
    QTableView *view = new QTableView;
    // 设置模型
    view->setModel(model);
    // 设置委托,这样可以下拉框显示
    view->setItemDelegate(new QSqlRelationalDelegate(view));
    view->setWindowTitle(title);
    return view;
}

上述代码:

  • 定义了一个名为 createView 的函数,函数用于创建一个新的 QTableView
  • 函数使用一个标题和一个 QSqlTableModel 对象作为参数,并使用传入的 QSqlTableModel 对象设置 view 的模型。
  • 使用 QSqlRelationalDelegate 设置 view 的委托,以便在需要显示下拉列表时使用。
  • 最后,函数设置 view 的窗口标题,并将 view 返回给调用者。
  1. // 调用
cpp 复制代码
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    if (!createConnection())
        return 1;

    QSqlRelationalTableModel model;

    initializeModel(&model);

    QTableView *view = createView(QObject::tr("Relational Table Model"), &model);
    view->show();

    return app.exec();
}

结果

注意

  • 表必须声明主键
  • 使用setRelation()方法时,关联的表和外键需存在,不然,错误的行不会加载到模型中,不会在视图中显示
  • 使用setItemDelegate(new QSqlRelationalDelegate(view))时,可以将单元格以下拉框方式显示

结论

重剑无锋,大巧不工

相关推荐
迦南的迦 亚索的索3 分钟前
PYTHON_DAY20_数据库
数据库·oracle
数厘13 分钟前
2.14 sql数据删除(DELETE、TRUNCATE)
数据库·oracle
XDHCOM25 分钟前
MySQL ER_ERROR_ENABLING_KEYS报错修复,远程处理索引启用失败故障,解决数据表锁定与性能瓶颈问题
数据库·mysql
高梦轩28 分钟前
Python 操作 MySQL 数据库
数据库·oracle
Arva .29 分钟前
Redis 数据类型
数据库·redis·缓存
CDN36035 分钟前
高防切换后网站打不开?DNS 解析与回源路径故障排查
前端·网络·数据库
笑我归无处1 小时前
Redis和数据库的数据一致性问题研究
数据库·redis·缓存
水痕011 小时前
使用sqlSugar来操作mysql数据库
数据库·mysql
zandy10111 小时前
衡石科技 HENGSHI SENSE:一站式智能分析平台,让企业数据价值“所见即所得”
大数据·数据库·科技
fly spider1 小时前
MySQL日志篇
数据库·mysql