Post

@ElementCollection

회원 데이터는 가능하면 여러 개의 권한을 가지도록 구성하는 것이 좋기 때문에 보통 @OneToMany,@ManyToMany 를 사용하여 여러 Entity 와 연관관계를 맺을 수 있으며, 연관관계를 맺을 때, 보통 ID 를 사용할 수 있을 것이라는 시뮬레이션을 할 것이다.

허나 얼마 지나지 않아 이러한 엔티티들의 테이블 구조가 복잡해질 것이라는 막막함도 동시에 떠오를 수 있을 것이다.
그래서 일단 하나의 엔티티 객체에 여러 값을 표현할 수 있는 @ElementCollection을 이용하여 회원관리 구성을 해보도록 하겠다.


  • MemberRole.java
1
2
3
4
public enum MemberRole {

    USER, ADMIN;
}

각 회원은 ‘USER’ 혹은 ‘ADMIN’ 등 회원 권한을 가질 수 있도록 Member 엔티티 클래스를 생성하고 @ElementCollection으로 처리해보도록 하겠다.


  • Member 엔티티 클래스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Entity
@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "roleSet")
public class Member extends BaseEntity{

    @Id
    private String mid;

    private String mpw;
    private String email;
    private boolean del;

    private boolean social;

    @ElementCollection(fetch = FetchType.LAZY)
    @Builder.Default
    private Set<MemberRole> roleSet = new HashSet<>();

    public void changePassword(String mpw){
        this.mpw = mpw;
    }

    public void changeEmail(String email){
        this.email = email;
    }

    public void changeDel(boolean del){
        this.del = del;
    }

    public void addRole(MemberRole memberRole){
        this.roleSet.add(memberRole);
    }

    public void clearRoles(){
        this.roleSet.clear();
    }

    public void changeSocial(boolean social){
        this.social = social;
    }
}

다음으로 Memberrepository 인터페이스를 하나 생성해서 제대로 로그인이 진행되는지 테스트를 해보자.
MemberRole을 같이 로딩할 수 있도록 @EntityGraph를 추가하고 일반 회원들만 가져오도록 social속성값이 false인 사용자들만 대상으로 처리하였다.


  • MemberRepository 인터페이스
1
2
3
4
5
6
public interface MemberRepository extends JpaRepository<Member,String> {

    @EntityGraph(attributePaths = "roleSet")
    @Query("select m from Member m where m.mid = :mid and m.social = false")
    Optional<Member> getWithRoles(@Param("mid") String mid);
}
  • Test 케이스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@SpringBootTest
@Log4j2
public class MemberRepositoryTest {

    @Autowired
    private MemberRepository memberRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Test
    public void insertMembers(){

        IntStream.rangeClosed(1,100).forEach(i ->{
            Member member = Member.builder()
                    .mid("member"+i)
                    .mpw(passwordEncoder.encode("1111"))
                    .email("email"+i+"@aaa.bbb")
                    .build();

            member.addRole(MemberRole.USER);
            if(i >= 90){
                member.addRole(MemberRole.ADMIN);
            }
            memberRepository.save(member);
        });
    }

}


테스트 케이스를 실행하고 나면 member 테이블과 member_role_sets 테이블이 생성되었고, member 테이블에는 100개의 사용자 데이터가 생성되었다.
20231128-member-table

동시에 member_role_sets 테이블에는 member90이상인 계정들은 0과 1이라는 값을 가지게 된다.

20231128-memberrolesets


This post is licensed under CC BY 4.0 by the author.