scalikeJDBC One-to-X API 사용하기(1:N:N편)

9813 단어 scalikeJDBCScala
scalikeJDBC One-to-X API 사용하기(기본편)의 속편입니다.
이번은 1:N:N의 테이블의 취급 방법에 대해입니다.

One-to-X API Document 를 보면 toManies로 1:N:N의 취득을 할 수 있을 것 같습니다만, 거기에는 함정이 있어・・・😱
3개의 테이블이 이어져 있는 형태의 1:N:N의 경우는 groupBy를 하지 않으면 의도하지 않은 형태로 데이터를 취급해 버릴 가능성이 있어 위험합니다.

우선 상황의 확인으로부터 하고 싶습니다.



이런 관계의 3개의 테이블이 있다고 합니다.

이것을 다음과 같이 표시하고 싶습니다.



기업에 따라서는 사업부와 유저의 등록을 하고 있지 않을지도 모르기 때문에, 이러한 블랭크의 표시 두가지 패턴도 있습니다.



이때 DB에서 얻은 값은 👇처럼
기업에 복수의 사업부가 끈을 두고 있어, 사업부에 대해서 복수의 유저가 연결해 주었으면 좋겠네요.



이것을 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입니다.
이것은 그림으로 나타내면 이런 식으로 얻어집니다.



이 시점에서 어떤 기업의 사용자는 어떤 사업부에 연결되어 있는지를 나타내지 않습니다 ... 😱
그래서 사용자를 사업부 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의 코드내에서 같은 것을 표현할 수 있다면 알고 싶습니다・・・)

좋은 웹페이지 즐겨찾기