QSqlRelationalTable 如何在具有外键的列中显示来自其他 table 的值?
QSqlRelationalTable How to display value from other table in a column with foreign key?
我有一个包含三个 table 的 SQLite 数据库:
graph(ID int primary key, name varchar(64));
vertex(ID int primary key, graphID int references graph(ID), name varchar(64), x int default 0, y int default 0);
edge(ID int primary key, graphID int references graph(ID), sourceID int references vertex(ID), targetID int references vertex(ID), weight real default 1);
在我的桌面应用程序中,我为 model/view
使用自定义 classes
MyTableView : public QTableView
VertexTableModel : public QSqlTableModel
EdgeTableModel : public QSqlRelationalTableModel
我是这样设置的:
GraphyEditor::GraphyEditor(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::GraphyEditor),
vertexModel(new VertexTableModel(parent)),
edgeModel(new EdgeTableModel(parent)) {
ui->setupUi(this);
vertexModel->setTable("vertex");
ui->vertices->setModel(vertexModel); // ui->vertices is *MyTableView
edgeModel->setTable("edge");
//TODO find fix to the issue
// edgeModel->setRelation(2, QSqlRelation("vertex", "ID", "name"));
// edgeModel->setRelation(3, QSqlRelation("vertex", "ID", "name"));
ui->edges->setModel(edgeModel); // ui->egdes is *MyTableView
}
此代码有效并正确显示数据,但我想将 edgeModel
中的第 2 列和第 3 列(sourceID
和 targetID
)从 vertex.ID
替换为vertex.name
我进行了一些搜索并找到了 setRelation
方法(与我在代码中注释掉的方法相同),但是当我使用它时 edgeModel
table 没有显示边缘。
是因为我的 table 模式还是我的代码有问题?
如何实现?
编辑:
以下是我正在使用的 classes 的实现:
MyTableModel.h/cpp
#include <QtSql/QSqlTableModel>
class MyTableModel : public QSqlTableModel {
Q_OBJECT
public:
explicit MyTableModel(QObject *parent = nullptr);
void refresh();
[[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override = 0;
bool setData(const QModelIndex &index, const QVariant &value, int role) override = 0;
signals:
void databaseUpdated();
};
#endif
#include "MyTableModel.h"
#include <QDebug>
#include <utility>
#include <database/DBManager.h>
MyTableModel::MyTableModel(QObject *parent) :
QSqlTableModel(parent) {}
void MyTableModel::refresh() { select(); }
VertexTableModel.h/cpp
#include <model/MyTableModel.h>
class VertexTableModel : public MyTableModel {
Q_OBJECT
public:
explicit VertexTableModel(QObject *parent = nullptr);
[[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
};
#endif
bool VertexTableModel::setData(const QModelIndex &index, const QVariant &value, int role) {
// checks if value is valid and updates database
}
Qt::ItemFlags VertexTableModel::flags(const QModelIndex &index) const {
auto flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (index.column() == 2) flags |= Qt::ItemIsEditable;
return flags;
}
VertexTableModel::VertexTableModel(QObject *parent) : MyTableModel(parent) {}
EdgeTableModel.h/cpp
class EdgeTableModel : public QSqlRelationalTableModel {
Q_OBJECT
public:
explicit EdgeTableModel(QObject *parent = nullptr);
void refresh();
[[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
signals:
void databaseUpdated();
};
#endif
EdgeTableModel::EdgeTableModel(QObject *parent) : QSqlRelationalTableModel(parent) {
refresh();
}
void EdgeTableModel::refresh() { select(); }
bool EdgeTableModel::setData(const QModelIndex &index, const QVariant &value, int role) {
// checks if value is valid and updates the database
}
Qt::ItemFlags EdgeTableModel::flags(const QModelIndex &index) const {
auto flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (index.column() == 4) flags |= Qt::ItemIsEditable;
return flags;
}
GraphyEditor.h/cpp
#ifndef GRAPHY_EDITOR_H
#define GRAPHY_EDITOR_H
#include <QMainWindow>
#include <model/vertex/VertexTableModel.h>
#include <model/edge/EdgeTableModel.h>
#include <QtGui/QRegExpValidator>
#include <QtSql/QSqlRelationalDelegate>
QT_BEGIN_NAMESPACE
namespace Ui { class GraphyEditor; }
QT_END_NAMESPACE
class GraphyEditor : public QMainWindow {
Q_OBJECT
Ui::GraphyEditor *ui;
QSqlTableModel *vertexModel;
QSqlRelationalTableModel *edgeModel;
QSqlRelationalDelegate *delegate;
QString graphID = "";
public:
explicit GraphyEditor(QWidget *parent = nullptr);
void setGraphID(const QString &newGraphID);
~GraphyEditor() override;
};
#endif
#include <QtWidgets/QWidget>
#include "GraphyEditor.h"
#include <model/vertex/VertexTableModel.h>
#include <model/edge/EdgeTableModel.h>
#include <QtSql/QSqlRelationalDelegate>
GraphyEditor::GraphyEditor(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::GraphyEditor),
// vertexModel(new VertexTableModel(parent)),
vertexModel(new QSqlTableModel(parent)),
// edgeModel(new EdgeTableModel(parent)) {
edgeModel(new QSqlRelationalTableModel(parent)) {
ui->setupUi(this);
vertexModel->setTable("vertex");
vertexModel->setHeaderData(1, Qt::Horizontal, "Vertex ID");
vertexModel->setHeaderData(2, Qt::Horizontal, "Vertex Name");
ui->vertices->setModel(vertexModel);
// ui->vertices->hideColumn(0);
ui->vertices->hideColumn(1);
ui->vertices->hideColumn(3);
ui->vertices->hideColumn(4);
edgeModel->setTable("edge");
//TODO find fix to the issue
// edgeModel->setRelation(2, QSqlRelation("vertex", "ID", "name"));
// edgeModel->setRelation(3, QSqlRelation("vertex", "ID", "name as targetName"));
edgeModel->setHeaderData(2, Qt::Horizontal, "Source Vertex", Qt::DisplayRole);
edgeModel->setHeaderData(3, Qt::Horizontal, "Target Vertex", Qt::DisplayRole);
edgeModel->setHeaderData(4, Qt::Horizontal, "Weight");
delegate = new QSqlRelationalDelegate(this);
ui->edges->setModel(edgeModel);
ui->edges->setItemDelegate(delegate);
// ui->edges->setItemDelegateForColumn(2, delegate);
// ui->edges->setItemDelegateForColumn(3, delegate);
ui->edges->hideColumn(0);
ui->edges->hideColumn(1);
ui->canvas->setVertices(vertexModel);
ui->canvas->setEdges(edgeModel);
}
GraphyEditor::~GraphyEditor() {
delete ui;
delete vertexModel;
delete edgeModel;
delete delegate;
}
void GraphyEditor::setGraphID(const QString &newGraphID) {
GraphyEditor::graphID = newGraphID;
vertexModel->setFilter("graphID = " + newGraphID);
edgeModel->setFilter("graphID = " + newGraphID);
ui->canvas->setGraphID(newGraphID);
ui->canvas->refresh();
}
GraphyCanvas.h/cpp
#ifndef GRAPHY_CANVAS_H
#define GRAPHY_CANVAS_H
#include <QWidget>
#include <model/vertex/VertexTableModel.h>
#include <model/edge/EdgeTableModel.h>
class GraphyCanvas : public QWidget {
Q_OBJECT
QSqlTableModel *vertexModel = nullptr;
QSqlRelationalTableModel *edgeModel = nullptr;
QString graphID = "";
public:
void setGraphID(const QString &newGraphID);
explicit GraphyCanvas(QWidget *parent = nullptr);
void setVertices(QSqlTableModel *vertexTableModel);
void setEdges(QSqlRelationalTableModel *edgeTableModel);
public slots:
void refresh();
};
#endif
#include <QPainter>
#include <QPen>
#include <QDebug>
#include <QtWidgets/QtWidgets>
#include <cmath>
#include "GraphyCanvas.h"
GraphyCanvas::GraphyCanvas(QWidget *parent) : QWidget(parent) {
QPalette newPalette = palette();
newPalette.setColor(QPalette::Window, Qt::white);
setPalette(newPalette);
}
void GraphyCanvas::refresh() {
vertexModel->select();
edgeModel->select();
for (auto child : children()) child->deleteLater();
int edgesCount = edgeModel->rowCount();
for (int e = 0; e < edgesCount; ++e) {
//paints edge objects
}
int verticesCount = vertexModel->rowCount();
for (int v = 0; v < verticesCount; ++v) {
//paints vertex objects
}
}
void GraphyCanvas::setVertices(QSqlTableModel *vertexTableModel) {
GraphyCanvas::vertexModel = vertexTableModel;
connect(vertexModel, SIGNAL(databaseUpdated()), this, SLOT(refresh()));
}
void GraphyCanvas::setEdges(QSqlRelationalTableModel *edgeTableModel) {
GraphyCanvas::edgeModel = edgeTableModel;
connect(edgeModel, SIGNAL(databaseUpdated()), this, SLOT(refresh()));
}
void GraphyCanvas::setGraphID(const QString &newGraphID) { GraphyCanvas::graphID = newGraphID; }
main.cpp
#include "setup/GraphySetup.h"
#include <QApplication>
#include <database/DBManager.h>
int main(int argc, char *argv[]) {
QApplication application(argc, argv);
DBManager::initialize();
GraphyEditor editor;
editor.setGraphID("1");
editor.showMaximized();
return QApplication::exec();
}
DBManager
是一个助手class,负责初始化和访问数据库
您的问题可能隐藏在项目的其他地方,您没有在问题中提供,但不在使用 QSqlRelationalTableModel 的代码中。
您的(注释)代码中只有一个最小的问题:两个替换的列将具有相同的名称:"name",但您可以在定义 QSqlRelation
时重命名这两列。
这是一个m.r.e。来说明如何处理你的两个表和一个 QSqlRelationalTableModel,以防万一其他人来 Whosebug 询问类似的问题。
SQLite 数据库转储:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE `vertex` (
`ID` INTEGER,
`name` TEXT,
PRIMARY KEY(`ID`)
);
INSERT INTO vertex VALUES(1,'one');
INSERT INTO vertex VALUES(2,'two');
INSERT INTO vertex VALUES(3,'three');
INSERT INTO vertex VALUES(4,'four');
INSERT INTO vertex VALUES(5,'five');
INSERT INTO vertex VALUES(6,'six');
INSERT INTO vertex VALUES(7,'seven');
INSERT INTO vertex VALUES(8,'eight');
INSERT INTO vertex VALUES(9,'nine');
CREATE TABLE IF NOT EXISTS "edge" (
"ID" INTEGER,
"sourceID" INTEGER,
"targetID" INTEGER,
FOREIGN KEY("targetID") REFERENCES "vertex"("ID"),
PRIMARY KEY("ID"),
FOREIGN KEY("sourceID") REFERENCES "vertex"("ID")
);
INSERT INTO edge VALUES(1,1,4);
INSERT INTO edge VALUES(2,2,5);
INSERT INTO edge VALUES(3,3,6);
INSERT INTO edge VALUES(4,4,7);
INSERT INTO edge VALUES(5,5,8);
INSERT INTO edge VALUES(6,6,9);
COMMIT;
test.pro
QT = core sql
CONFIG += c++11 console
SOURCES += main.cpp
main.cpp
#include <QCoreApplication>
#include <QTextStream>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlRelationalTableModel>
#include <QSqlRecord>
#include <QSqlField>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTextStream cout(stdout, QIODevice::WriteOnly);
QTextStream cerr(stderr, QIODevice::WriteOnly);
auto db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("test.db");
if (!db.open()) {
cerr << db.lastError().text() << endl;
return 1;
}
QSqlRelationalTableModel model;
model.setTable("edge");
model.setRelation(1, QSqlRelation("vertex", "ID", "name as sourceName"));
model.setRelation(2, QSqlRelation("vertex", "ID", "name as targetName"));
model.select();
auto rec = model.record();
// headers output
cout << qSetFieldWidth(15);
for(int i=0; i<rec.count(); ++i) {
cout << rec.field(i).name();
}
cout << endl;
// rows output
for(int i=0; i<model.rowCount(); ++i) {
rec = model.record(i);
cout << rec.value("ID").toInt() << rec.value("sourceName").toString() << rec.value("targetName").toString() << endl;
}
}
这是程序的输出:
ID sourceName targetName
1 one four
2 two five
3 three six
4 four seven
5 five eight
6 six nine
在GraphyEditor.cpp中,函数GraphyEditor::setGraphID
,这一行
edgeModel->setFilter("graphID = " + newGraphID);
应该是
edgeModel->setFilter("edge.graphID = " + newGraphID);
底层查询是一个join,其中字段名graphID属于多个table,所以必须指定table名称以及字段名称。
也许修改selectStatement
:
QString QSqlRelationalTableModel::selectStatement() const
......
//!!! my
fList.append(QLatin1String(", "));
fList.append(relTableAlias);
fList.append(QLatin1String("."));
fList.append(relation.indexColumn());
fList.append(QLatin1String(" as "));
fList.append(relation.tableName());
fList.append(QLatin1String("_"));
fList.append(relation.indexColumn());
我有一个包含三个 table 的 SQLite 数据库:
graph(ID int primary key, name varchar(64));
vertex(ID int primary key, graphID int references graph(ID), name varchar(64), x int default 0, y int default 0);
edge(ID int primary key, graphID int references graph(ID), sourceID int references vertex(ID), targetID int references vertex(ID), weight real default 1);
在我的桌面应用程序中,我为 model/view
使用自定义 classesMyTableView : public QTableView
VertexTableModel : public QSqlTableModel
EdgeTableModel : public QSqlRelationalTableModel
我是这样设置的:
GraphyEditor::GraphyEditor(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::GraphyEditor),
vertexModel(new VertexTableModel(parent)),
edgeModel(new EdgeTableModel(parent)) {
ui->setupUi(this);
vertexModel->setTable("vertex");
ui->vertices->setModel(vertexModel); // ui->vertices is *MyTableView
edgeModel->setTable("edge");
//TODO find fix to the issue
// edgeModel->setRelation(2, QSqlRelation("vertex", "ID", "name"));
// edgeModel->setRelation(3, QSqlRelation("vertex", "ID", "name"));
ui->edges->setModel(edgeModel); // ui->egdes is *MyTableView
}
此代码有效并正确显示数据,但我想将 edgeModel
中的第 2 列和第 3 列(sourceID
和 targetID
)从 vertex.ID
替换为vertex.name
我进行了一些搜索并找到了 setRelation
方法(与我在代码中注释掉的方法相同),但是当我使用它时 edgeModel
table 没有显示边缘。
是因为我的 table 模式还是我的代码有问题?
如何实现?
编辑:
以下是我正在使用的 classes 的实现:
MyTableModel.h/cpp
#include <QtSql/QSqlTableModel>
class MyTableModel : public QSqlTableModel {
Q_OBJECT
public:
explicit MyTableModel(QObject *parent = nullptr);
void refresh();
[[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override = 0;
bool setData(const QModelIndex &index, const QVariant &value, int role) override = 0;
signals:
void databaseUpdated();
};
#endif
#include "MyTableModel.h"
#include <QDebug>
#include <utility>
#include <database/DBManager.h>
MyTableModel::MyTableModel(QObject *parent) :
QSqlTableModel(parent) {}
void MyTableModel::refresh() { select(); }
VertexTableModel.h/cpp
#include <model/MyTableModel.h>
class VertexTableModel : public MyTableModel {
Q_OBJECT
public:
explicit VertexTableModel(QObject *parent = nullptr);
[[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
};
#endif
bool VertexTableModel::setData(const QModelIndex &index, const QVariant &value, int role) {
// checks if value is valid and updates database
}
Qt::ItemFlags VertexTableModel::flags(const QModelIndex &index) const {
auto flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (index.column() == 2) flags |= Qt::ItemIsEditable;
return flags;
}
VertexTableModel::VertexTableModel(QObject *parent) : MyTableModel(parent) {}
EdgeTableModel.h/cpp
class EdgeTableModel : public QSqlRelationalTableModel {
Q_OBJECT
public:
explicit EdgeTableModel(QObject *parent = nullptr);
void refresh();
[[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
signals:
void databaseUpdated();
};
#endif
EdgeTableModel::EdgeTableModel(QObject *parent) : QSqlRelationalTableModel(parent) {
refresh();
}
void EdgeTableModel::refresh() { select(); }
bool EdgeTableModel::setData(const QModelIndex &index, const QVariant &value, int role) {
// checks if value is valid and updates the database
}
Qt::ItemFlags EdgeTableModel::flags(const QModelIndex &index) const {
auto flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (index.column() == 4) flags |= Qt::ItemIsEditable;
return flags;
}
GraphyEditor.h/cpp
#ifndef GRAPHY_EDITOR_H
#define GRAPHY_EDITOR_H
#include <QMainWindow>
#include <model/vertex/VertexTableModel.h>
#include <model/edge/EdgeTableModel.h>
#include <QtGui/QRegExpValidator>
#include <QtSql/QSqlRelationalDelegate>
QT_BEGIN_NAMESPACE
namespace Ui { class GraphyEditor; }
QT_END_NAMESPACE
class GraphyEditor : public QMainWindow {
Q_OBJECT
Ui::GraphyEditor *ui;
QSqlTableModel *vertexModel;
QSqlRelationalTableModel *edgeModel;
QSqlRelationalDelegate *delegate;
QString graphID = "";
public:
explicit GraphyEditor(QWidget *parent = nullptr);
void setGraphID(const QString &newGraphID);
~GraphyEditor() override;
};
#endif
#include <QtWidgets/QWidget>
#include "GraphyEditor.h"
#include <model/vertex/VertexTableModel.h>
#include <model/edge/EdgeTableModel.h>
#include <QtSql/QSqlRelationalDelegate>
GraphyEditor::GraphyEditor(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::GraphyEditor),
// vertexModel(new VertexTableModel(parent)),
vertexModel(new QSqlTableModel(parent)),
// edgeModel(new EdgeTableModel(parent)) {
edgeModel(new QSqlRelationalTableModel(parent)) {
ui->setupUi(this);
vertexModel->setTable("vertex");
vertexModel->setHeaderData(1, Qt::Horizontal, "Vertex ID");
vertexModel->setHeaderData(2, Qt::Horizontal, "Vertex Name");
ui->vertices->setModel(vertexModel);
// ui->vertices->hideColumn(0);
ui->vertices->hideColumn(1);
ui->vertices->hideColumn(3);
ui->vertices->hideColumn(4);
edgeModel->setTable("edge");
//TODO find fix to the issue
// edgeModel->setRelation(2, QSqlRelation("vertex", "ID", "name"));
// edgeModel->setRelation(3, QSqlRelation("vertex", "ID", "name as targetName"));
edgeModel->setHeaderData(2, Qt::Horizontal, "Source Vertex", Qt::DisplayRole);
edgeModel->setHeaderData(3, Qt::Horizontal, "Target Vertex", Qt::DisplayRole);
edgeModel->setHeaderData(4, Qt::Horizontal, "Weight");
delegate = new QSqlRelationalDelegate(this);
ui->edges->setModel(edgeModel);
ui->edges->setItemDelegate(delegate);
// ui->edges->setItemDelegateForColumn(2, delegate);
// ui->edges->setItemDelegateForColumn(3, delegate);
ui->edges->hideColumn(0);
ui->edges->hideColumn(1);
ui->canvas->setVertices(vertexModel);
ui->canvas->setEdges(edgeModel);
}
GraphyEditor::~GraphyEditor() {
delete ui;
delete vertexModel;
delete edgeModel;
delete delegate;
}
void GraphyEditor::setGraphID(const QString &newGraphID) {
GraphyEditor::graphID = newGraphID;
vertexModel->setFilter("graphID = " + newGraphID);
edgeModel->setFilter("graphID = " + newGraphID);
ui->canvas->setGraphID(newGraphID);
ui->canvas->refresh();
}
GraphyCanvas.h/cpp
#ifndef GRAPHY_CANVAS_H
#define GRAPHY_CANVAS_H
#include <QWidget>
#include <model/vertex/VertexTableModel.h>
#include <model/edge/EdgeTableModel.h>
class GraphyCanvas : public QWidget {
Q_OBJECT
QSqlTableModel *vertexModel = nullptr;
QSqlRelationalTableModel *edgeModel = nullptr;
QString graphID = "";
public:
void setGraphID(const QString &newGraphID);
explicit GraphyCanvas(QWidget *parent = nullptr);
void setVertices(QSqlTableModel *vertexTableModel);
void setEdges(QSqlRelationalTableModel *edgeTableModel);
public slots:
void refresh();
};
#endif
#include <QPainter>
#include <QPen>
#include <QDebug>
#include <QtWidgets/QtWidgets>
#include <cmath>
#include "GraphyCanvas.h"
GraphyCanvas::GraphyCanvas(QWidget *parent) : QWidget(parent) {
QPalette newPalette = palette();
newPalette.setColor(QPalette::Window, Qt::white);
setPalette(newPalette);
}
void GraphyCanvas::refresh() {
vertexModel->select();
edgeModel->select();
for (auto child : children()) child->deleteLater();
int edgesCount = edgeModel->rowCount();
for (int e = 0; e < edgesCount; ++e) {
//paints edge objects
}
int verticesCount = vertexModel->rowCount();
for (int v = 0; v < verticesCount; ++v) {
//paints vertex objects
}
}
void GraphyCanvas::setVertices(QSqlTableModel *vertexTableModel) {
GraphyCanvas::vertexModel = vertexTableModel;
connect(vertexModel, SIGNAL(databaseUpdated()), this, SLOT(refresh()));
}
void GraphyCanvas::setEdges(QSqlRelationalTableModel *edgeTableModel) {
GraphyCanvas::edgeModel = edgeTableModel;
connect(edgeModel, SIGNAL(databaseUpdated()), this, SLOT(refresh()));
}
void GraphyCanvas::setGraphID(const QString &newGraphID) { GraphyCanvas::graphID = newGraphID; }
main.cpp
#include "setup/GraphySetup.h"
#include <QApplication>
#include <database/DBManager.h>
int main(int argc, char *argv[]) {
QApplication application(argc, argv);
DBManager::initialize();
GraphyEditor editor;
editor.setGraphID("1");
editor.showMaximized();
return QApplication::exec();
}
DBManager
是一个助手class,负责初始化和访问数据库
您的问题可能隐藏在项目的其他地方,您没有在问题中提供,但不在使用 QSqlRelationalTableModel 的代码中。
您的(注释)代码中只有一个最小的问题:两个替换的列将具有相同的名称:"name",但您可以在定义 QSqlRelation
时重命名这两列。
这是一个m.r.e。来说明如何处理你的两个表和一个 QSqlRelationalTableModel,以防万一其他人来 Whosebug 询问类似的问题。
SQLite 数据库转储:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE `vertex` (
`ID` INTEGER,
`name` TEXT,
PRIMARY KEY(`ID`)
);
INSERT INTO vertex VALUES(1,'one');
INSERT INTO vertex VALUES(2,'two');
INSERT INTO vertex VALUES(3,'three');
INSERT INTO vertex VALUES(4,'four');
INSERT INTO vertex VALUES(5,'five');
INSERT INTO vertex VALUES(6,'six');
INSERT INTO vertex VALUES(7,'seven');
INSERT INTO vertex VALUES(8,'eight');
INSERT INTO vertex VALUES(9,'nine');
CREATE TABLE IF NOT EXISTS "edge" (
"ID" INTEGER,
"sourceID" INTEGER,
"targetID" INTEGER,
FOREIGN KEY("targetID") REFERENCES "vertex"("ID"),
PRIMARY KEY("ID"),
FOREIGN KEY("sourceID") REFERENCES "vertex"("ID")
);
INSERT INTO edge VALUES(1,1,4);
INSERT INTO edge VALUES(2,2,5);
INSERT INTO edge VALUES(3,3,6);
INSERT INTO edge VALUES(4,4,7);
INSERT INTO edge VALUES(5,5,8);
INSERT INTO edge VALUES(6,6,9);
COMMIT;
test.pro
QT = core sql
CONFIG += c++11 console
SOURCES += main.cpp
main.cpp
#include <QCoreApplication>
#include <QTextStream>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlRelationalTableModel>
#include <QSqlRecord>
#include <QSqlField>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTextStream cout(stdout, QIODevice::WriteOnly);
QTextStream cerr(stderr, QIODevice::WriteOnly);
auto db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("test.db");
if (!db.open()) {
cerr << db.lastError().text() << endl;
return 1;
}
QSqlRelationalTableModel model;
model.setTable("edge");
model.setRelation(1, QSqlRelation("vertex", "ID", "name as sourceName"));
model.setRelation(2, QSqlRelation("vertex", "ID", "name as targetName"));
model.select();
auto rec = model.record();
// headers output
cout << qSetFieldWidth(15);
for(int i=0; i<rec.count(); ++i) {
cout << rec.field(i).name();
}
cout << endl;
// rows output
for(int i=0; i<model.rowCount(); ++i) {
rec = model.record(i);
cout << rec.value("ID").toInt() << rec.value("sourceName").toString() << rec.value("targetName").toString() << endl;
}
}
这是程序的输出:
ID sourceName targetName
1 one four
2 two five
3 three six
4 four seven
5 five eight
6 six nine
在GraphyEditor.cpp中,函数GraphyEditor::setGraphID
,这一行
edgeModel->setFilter("graphID = " + newGraphID);
应该是
edgeModel->setFilter("edge.graphID = " + newGraphID);
底层查询是一个join,其中字段名graphID属于多个table,所以必须指定table名称以及字段名称。
也许修改selectStatement
:
QString QSqlRelationalTableModel::selectStatement() const
......
//!!! my
fList.append(QLatin1String(", "));
fList.append(relTableAlias);
fList.append(QLatin1String("."));
fList.append(relation.indexColumn());
fList.append(QLatin1String(" as "));
fList.append(relation.tableName());
fList.append(QLatin1String("_"));
fList.append(relation.indexColumn());