2016-11-01 15 views
0

テーブル '人物'には、次の列があります。 id、name、manager_id。 'id'は主キーで、 'manager_id'は外部キーです。管理者がいる人もいるので、この値はNULLにすることができます。しかし、これはQtのQSqlRelationalTableModelに問題を引き起こすようです。ここでQt:QSqlRelationalTableModel非存在外キーへの参照

は、問題を複製最小限の例です: window.cpp:

Window::Window(QWidget *parent) : QWidget(parent) 
{ 
// setup database 
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); 
db.setDatabaseName(":memory:"); 
db.open(); 

// create database 
QSqlQuery query; 
query.exec("create table 'person' (id INTEGER NOT NULL PRIMARY KEY, " 
      "name varchar(20), manager_id INTEGER NULL)"); 
query.exec("insert into person values(1, 'Alice', 2)"); 
query.exec("insert into person values(2, 'Bob', -1)"); // invalid manager_id 
//query.exec("insert into person values(2, 'Bob', 1)"); // valid example 

// setup model 
model = new QSqlRelationalTableModel(this); 
model->setTable("person"); 
model->setEditStrategy(QSqlTableModel::OnRowChange); 

// setup foreign key 
int typeIndex = model->fieldIndex("manager_id"); 
model->setRelation(typeIndex, QSqlRelation("person", "id", "name")); 
model->select(); 

// setup UI 
auto nameLabel = new QLabel(tr("Name:")); auto nameEdit = new QLineEdit(); 
auto typeLabel = new QLabel(tr("Manager:")); auto typeComboBox = new QComboBox(); 
auto nextButton = new QPushButton(tr("Next")); 
auto previousButton = new QPushButton(tr("Previous")); 
QSqlTableModel *relModel = model->relationModel(typeIndex); 
typeComboBox->setModel(relModel); 
typeComboBox->setModelColumn(relModel->fieldIndex("name")); 
QGridLayout *layout = new QGridLayout(); 
layout->addWidget(nameLabel, 0, 0, 1, 1); 
layout->addWidget(nameEdit, 0, 1, 1, 1); 
layout->addWidget(previousButton, 0, 2, 1, 1); 
layout->addWidget(nextButton, 1, 2, 1, 1); 
layout->addWidget(typeLabel, 2, 0, 1, 1); 
layout->addWidget(typeComboBox, 2, 1, 1, 1); 
setLayout(layout); 

// setup mapper 
mapper = new QDataWidgetMapper(this); 
mapper->setModel(model); 
mapper->setItemDelegate(new QSqlRelationalDelegate(this)); 
mapper->addMapping(nameEdit, model->fieldIndex("name")); 
mapper->addMapping(typeComboBox, typeIndex); 
mapper->toFirst(); 

connect(previousButton, SIGNAL(clicked()), mapper, SLOT(toPrevious())); 
connect(nextButton, SIGNAL(clicked()), mapper, SLOT(toNext())); 
} 

window.h:

#include <QWidget> 
class QDataWidgetMapper; 
class QSqlRelationalTableModel; 
class Window : public QWidget 
{ 
    Q_OBJECT 
public: 
    Window(QWidget *parent = 0); 
private slots: 
private: 
    QDataWidgetMapper *mapper; 
    QSqlRelationalTableModel *model; 
}; 

問題は、第二のレコード(すなわち、 "ボブ" ということですマネージャのIDが無効(-1)なので表示されません。

QSqlRelationalTableModelのドキュメントには、 が記載されています。「リレーショナル表には、参照先表の存在しない行を参照するキーが含まれていると、無効なキーを含む行はモデルを通じて公開されません。参照整合性を維持する責任があります。

しかし、これを回避する手段はありませんか?これは共通の問題だと私には思われます。ありがとう。

+0

私が思いつくことができる "汚い"解決策は、テーブルに「ダミー」行を追加し、それに応じて値を変更することです。query.exec(「人の値(1、 ''、-1) ");しかし、これはかなり厄介なようです。 – user1829358

答えて

1

データの説明によれば、「管理者なし」は許容値であるため、無効とみなすのは意味がありません。

あなたの例の実際の問題は、name列にいくつかの重なり合う斑点があることです。実際には別のnamesテーブルである必要があります。このテーブルには、空の文字列を持つ行があり、「マネージャなし」を示すことができます。

personテーブルには、namesテーブルのIDだけが含まれます。

+0

これは私が投稿したコメントのようなものではありませんか?それは私にとっては汚い解決策のようだ。さらに、私は同じテーブルへの参照に問題は見られません。これはデータベース設計の一般的な状況ではありませんか? – user1829358

+0

@ user1829358私にとっては、すべての名前を別のテーブルに入れるのは自然で効率的な解決策です。しかし、すべてを1つのテーブルに入れることを余儀なくされた場合、制約が私の特定のニーズに合わない場合は、 'QSqlRelationalTableModel'のような便利なクラスを使用しても構いません。実際には、他のデータベーステーブルを実際に参照していない場合は、かなり重いソリューションのように見えます。 – ekhumoro

関連する問題