ここまでの例ではscalikejdbcGenで自動生成されたメソッドや単一テーブルに対するシンプルなQueryDSLで処理できる例ばかりでしたが、ここではもう少し実践的な検索処理の実装方法について紹介します。

INNER JOIN

INNER JOINの場合はシンプルにinnerJoinメソッドを使用します。検索結果の取得もシンプルです。以下の例ではUSERSテーブルとCOMPANIESテーブルをINNER JOINし、検索結果をそれぞれのモデルクラスのタプルのシーケンスで取得しています。

val users: Seq[(Users, Companies)] = withSQL {
  select.from(Users as u).innerJoin(Companies as c).on(u.companyId, c.id)
}.map { rs =>
  (Users(u)(rs), Companies(c)(rs))
}.list.apply()

LEFT JOIN

LEFT JOINの場合はleftJoinメソッドを使用します。

val users: Seq[(Users, Option[Companies])] = withSQL {
  select.from(Users as u).leftJoin(Companies as c).on(u.companyId, c.id)
}.map { rs =>
  (Users(u)(rs), rs.intOpt(c.resultName.id).map(_ => Companies(c)(rs)))
}.list.apply()

LEFT JOINしたテーブルの値を取得する場合、map()メソッドでOption型に変換する必要があるという点に注意してください。以下のコードは、まず結果セットからCOMPANIESテーブルのIDカラムをintOptメソッドでOption[Int]型として取得し、値が取得できた場合のみCompaniesクラスにマッピングするという処理を行っています。

rs.intOpt(c.resultName.id).map(_ => Companies(c)(rs))

SQLを直接記述する

sql interpolationを使うと文字列リテラルで生SQLを記述することができます。ただし、SQLを完全に記述するだけでなく、自動生成されたクラスを使って記述を補助することができます。

val users: Seq[(Users, Companies)] = sql"""
  |SELECT ${u.result.*}, ${c.result.*}
  |FROM ${Users.as(u)} INNER JOIN ${Companies.as(c)}
  |ON ${u.companyId} = ${c.id}
""".stripMargin.map { rs =>
  (Users(u)(rs), Companies(c)(rs))
}.list.apply()

SELECT句に大量のカラムを記述する必要がなかったり、テーブル名やカラム名のタイプミスを防ぐことができます。また、sql interpolationを使う場合はwithSQL { ... }で囲む必要はありません。map()メソッド以降はQueryDSLの場合と同じです。

参考資料

ScalikeJDBCの詳細については以下のドキュメントが参考になります。