단두린더의 연관관계는 유저와 그룹이 다대다로 이를 일대다 다대일로 풀어서 해결했다.
그런데..! 잘 해결된줄 알았는데 막상 스프링 데이터 JPA를 적용하려하니 UserGroup 이자식의 키값을 뭘로 써야할지 너무 애매한거다..!
왜냐하면
// User
public class User {
@Id
private String user_id;
private String user_name;
@OneToMany(mappedBy = "user")
private List<UserGroup> userGroups = new ArrayList<>();
// 생략
}
// Group
public class Group {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long group_id;
@OneToMany(mappedBy = "group")
private List<UserGroup> userGroups = new ArrayList<>();
// 생략
}
// UserGroup
public class UserGroup {
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "group_id")
private Group group;
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
// 생략
}
바로 아이디가 두개 이상 즉 복합키로 되어 있었다.
열심히 서치 해보니 이럴때는 두가지 방법이 있는데 @IdClass와 @EmbeddedId 를 사용해서 해결할 수 있다고 한다.
IdClass는 좀 더 직관적이고 값을 직접 조회할 수 있는 반면, EmbeddedId는 뎁스가 한 단계 더 깊어진다고 한다..
객체지향적인 관점에서 @EmbeddedId로 구현할 수 있는 장점이 있어 나는 이번에 EmbeddedId를 사용해보았다.
우선 EmbeddedId를 사용하기 위해서 클래스를 하나 더 생성해줘야 한다. 이 클래스가 JpaRepository<T(엔티티 타입), ID (식별자 타입 PK)> ID 식별자 값으로 들어간다.
@Embeddable
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class UserGroupId implements Serializable {
@Column(name = "user_id")
private String userId;
@Column(name = "group_id")
private Long groupId;
}
EmbeddedId 방식을 사용하면 필수로 지켜야 하는 방식이 있다고 하는데 public 깡통 생성자와 equal & hashCode 오버라이드, serializable... 암튼 열심히 룰에 맞춰 클래스를 생성한다.
유저그룹의 복합키 두 개를 가져와 각각 찐 키값의 타입으로 설정해준다. 유저아이디, 그룹아이디 설정
@Entity
@Getter
@Builder
@AllArgsConstructor
@DynamicInsert
public class UserGroup {
@EmbeddedId
private UserGroupId id;
@MapsId("groupId")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "group_id")
private Group group;
@MapsId("userId")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
protected UserGroup() {
}
}
에러 해결 : must not have @Id properties when used as an @EmbeddedId:
여기서 제목에 적은 에러를 해결할 수 있었다..
복합키 두개가 사실은 유저와 그룹을 외래키로 연결해줘야한다. 그것을 연결 하는게 바로 @MapsId 이다..!! 이 전에는 모르고 @Id를 둘다 할당해줘서 썼는데 맵스아이디라는 친구가 있었다.
바붕 ㅠ MpapsId에 변수명 잘 할당 해주면 끝난다.
아맞다 @EmbeddedId는 우리가 바로 전에 만들어준 UserGroupId로 넣어주면 끝!
Q. userId를 사용해서 UserGroup을 얻어오려면 어떻게 해야하나요?
그러니까 복합키 중 키 값 하나만 사용해서 값을 얻어오고 싶다.
아놔 진짜 Spring Data JPA는 findById 해서 ID에 UserGroupId 를 넣게 되어 있다.. ㅠ 씨잉 이거 진짜 어케 찾는거란 말이야~!~!
UserGroupId userGroupId = UserGroupId.builder().userId(userId).build();
Optional<UserGroup> byId = userGroupRepository.findById(userGroupId);
삽질 삽질
이렇게 찾으면 조건절에 groupId=null and userId='' 이렇게 들어가서 그룹아이디 설정도 안해줬는데 .. 결국 최종 리턴값이 null로 나온다. 흑
암튼 열심히 찾아낸 결과
public interface UserGroupRepository extends JpaRepository<UserGroup, UserGroupId> {
Optional<UserGroup> findByIdUserId(String userId);
}
Repository에서 메소드명으로 구현하기~!를 활용해서 findByIdUserId 라고 해주면 된다.
Hibernate:
select
usergroup0_.group_id as group_id1_4_,
usergroup0_.user_id as user_id2_4_,
usergroup0_.modr_id as modr_id3_4_,
usergroup0_.reg_dt as reg_dt4_4_,
usergroup0_.regr_id as regr_id5_4_
from
UserGroup usergroup0_
where
usergroup0_.user_id=?
그러면 쿼리도 userId 알아서 잘 서치해서 나간다. 유후~!
'프로젝트' 카테고리의 다른 글
SpringBoot로 그룹캘린더 만들기 시즌2 - 스프링 데이터 JPA를 활용 (0) | 2023.07.11 |
---|---|
SpringBoot로 그룹캘린더 만들기 시즌2 - ERD 수정 (0) | 2023.07.11 |
SpringBoot로 그룹캘린더 만들기 시즌2 - 코드 리팩토링 (1) | 2023.06.28 |
SpringBoot로 그룹캘린더 만들기 - Spring Security 로그아웃 구현하기 (0) | 2023.04.25 |
SpringBoot로 그룹캘린더 만들기 - Spring Security, OAuth2 사용하기 (네이버, 카카오 회원가입 및 로그인) (0) | 2023.04.24 |