KotlinのExposedでつまづいたときのお話です。
ここを参考に。
#問題
外部キー制約がないテーブル同士をinnerJoin
で結合しようとするとエラーになってしまう
(there is no matching primary key/foreign key pair and constraint missing
)
#解決方法
innerJoin
メソッドではなく、join
メソッドを使用します。
##詳細
以下のようにします。
UserTable.join(TodoTable, JoinType.INNER, UserTable.id, TodoTable.userId)
上記のコードを見ていただければ使い方は大体わかると思いますが、引数は以下のようになっています。
(結合するテーブル、結合のタイプ、結合条件に使用するカラム1、結合条件に使用するカラム2)
上記のコードを実行すると、以下のSQLが生成されます。
SELECT `user`.id, `user`.`name`, Todo.id, Todo.title, Todo.done, Todo.user_id FROM `user` INNER JOIN Todo ON `user`.id = Todo.user_id
また、5つ目の引数として、追加条件を渡すことも可能です。
UserTable.join(TodoTable, JoinType.INNER, UserTable.id, TodoTable.userId) {
UserTable.name eq TodoTable.title
}.selectAll().toList()
上記を実行すると以下のようになります。
SELECT `user`.id, `user`.`name`, Todo.id, Todo.title, Todo.done, Todo.user_id FROM `user` INNER JOIN Todo ON `user`.id = Todo.user_id AND (`user`.`name` = Todo.title)
#原因
ExposedのinnerJoin
leftJoin
rightJoin
は、使用する際にテーブル結合するテーブル同士に存在する外部キー制約にのっとった結合条件を使用するようです。つまり、以下のようなテーブルでinnerJoin
をしようとすると、
object UserTable : Table("users") {
val id = uuid("id")
val name = varchar("name", 20)
}
object TodoTable : Table() {
val id = integer("id")
val title = varchar("title", 50)
val done = bool("done")
//ユーザーテーブルへの外部キーを持つ
val userId = uuid("user_id").references(UserTable.id)
}
//innserJoinをやってみる
TodoTable.innerJoin(UserTable).selectAll().toList()
以下のようなSQLを生成しようとします。
SELECT Todo.id, Todo.title, Todo.done, Todo.user_id, `user`.id, `user`.`name` FROM Todo INNER JOIN `user` ON `user`.id = Todo.user_id
TodoTable.innerJoin(UserTable).selectAll().toList()
では特に条件を指定しなくとも、外部キーによる結合条件が自動的に入っていることがわかると思います。
ここで、仮に結合テーブルに外部キー制約がないと、結合条件がわからないということでthere is no matching primary key/foreign key pair and constraint missing
が発生して落ちてしまうわけですね。