4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

scalikeJDBC One-to-X APIを使いこなす(1:N:N編)

Last updated at Posted at 2020-01-23

scalikeJDBC One-to-X APIを使いこなす(基本編)の続編です。
今回は1:N:Nのテーブルの扱い方についてです。

One-to-X API Document をみるとtoManiesで1:N:Nの取得ができそうですが、そこには落とし穴があり・・・😱
3つのテーブルが連なっている形の1:N:Nの場合はgroupByをしないと意図しない形でデータを扱ってしまう可能性があり危険です。

まずシチュエーションの確認からしたいと思います。

iOS の画像.jpg

こういう関係の3つのテーブルがあったとします。

これを、以下のように表示したいとします。

iOS の画像 (1).jpg

企業によっては、事業部とユーザーの登録をしていないかもしれないので、こういったブランクの表示二なるパターンもあります。

iOS の画像 (2).jpg

このとき、DBから取得した値は👇のように、
企業に複数の事業部がひもづいていて、事業部に対して複数のユーザーが紐づいて欲しいですね。

iOS の画像 (2).jpg

これをtoManiesで書いてみます🎉

withSQL[Corporates] {
  select
    .from(Corporates.as(corporatesTable))
    .leftJoin(Departments.as(departmentsTable))
    .on(corporatesTable.corporateId, departmentsTable.corporateId)
    .leftJoin(Users.as(usersTable))
    .on(departmentsTable.departmentId, usersTable.departmentId)
}.one(Corporates(corporatesTable))
  .toManies(
    rs => rs.longOpt(departmentsTable.resultName.corporateId).map(_ => Departments(departmentsTable)(rs)),
    rs => rs.longOpt(usersTable.resultName.departmentId).map(_ => Users(usersTable)(rs)),
  )
  .map((corporate, departments, users) => (corporate, departments, users))
  .list()
  .apply()

前回の記事 を参考に書くと、こういう感じになります。
ここで、この行に注目してください、

.map((corporate, departments, users) => (corporate, departments, users))

怪しさMAXですね。
これは図で表すと、こういう形で取得されています。

iOS の画像 (3).jpg

この時点では、ある企業のユーザーは、どの事業部に紐づているのかを表せていません・・・😱
なので、ユーザーを事業部IDでグルーピングしてあげる必要があります。
もしそれを考慮せずに👇このようにしてしまうと、ある企業のすべての事業部に同じユーザーが所属しているような表示になってしまいます。
グルーピングを忘れるだけで、大惨事を起こしかねません。

.map((corporate, departments, users) => 
CorporatesModel(corporate.name, departments.map(department => DepartmensModel(department.name, users.map(user => UsersModel(user.name)))))

グルーピングをするためには、このように書くのが良さそうです。

  ...
  .map((corporate, departments, users) =>
     val groupedUsers: Map[Long, Seq[Users]] = users.groupBy(user => user.departmentId)
     CorporatesModel(corporate.name, departments.map(department => DepartmensModel(department.name), groupedUsers(departments.departmentId).map(user => UsersModel(user.name)))  
  )
 ...

groupByを使ってusersをMAP型にし、departmentIdで束ねてある形にします。
これで、ある事業部にユーザーが紐づいている、という正しい形にマッピングすることができます👏
そして、正しいタイミングで事業部IDを元にユーザーのリストを取得すれば欲しいモデルの形に変換することができました。

1:NであればscalikeJDBC内で対応でき流のでグルーピングの考慮は不要ですが、
1:N:N...だと考慮が必要であり、このように実装するのがベストだと思っています。
(※もしscalikeDJBCのコード内で同じことが表現できるのであれば知りたいです・・・)

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?