Dev/JPA

JPA ์—ฐ๊ด€๊ด€๊ณ„ (1:N)

OK-๊ฐ€์ž 2022. 3. 2. 17:24

๐Ÿ˜Ž1:N ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ์•Œ์•„๋ณด์ž.


์œ„์˜ user Table๊ณผ user_history๋Š” 1๋Œ€ N ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค.

โœ… ์ด์ „์— ๋งŒ๋“  User์™€ User_history ์—”ํ‹ฐํ‹ฐ๋“ค์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋ฉด๋œ๋‹ค. Test ํ•ด๋ณด์ž.

    @Test
    void userRelationTest(){
        User user = new User();
        user.setName("david");
        user.setEmail("david@fast.com");
        user.setGender(Gender.MALE);

        userRepository.save(user);

        userHistoryRepository.findAll().forEach(System.out::println);
    }
๊ฒฐ๊ณผ
UserHistory(super=BaseEntity(createdAt=2022-02-08T14:23:00.755, updatedAt=2022-02-08T14:23:00.755), id=1, userId=null, name=david, email=david@fast.com)

UserHistory์˜ userId ๊ฐ’์ด null๋กœ ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๋Š”๋ฐ.. ์ด์œ ๋Š” PrePersist๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋””๋น„์— ๋“ค์–ด๊ฐ€๊ธฐ ์ „์— ์ฟผ๋ฆฌ๋ฅผ ๋•Œ๋ ค์„œ ๊ทธ๋Ÿฐ๊ฑฐ ๊ฐ™๋‹ค. ๊ทธ๋Ÿผ PostPersist๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์ž.

public class UserEntityListener {

    @PostPersist
    @PostUpdate
    public void prePersistAndPreUpdate(Object o) {
...
...
...

โœ… ๊ฐ™์€ ์œ ์ €์— ๋Œ€ํ•ด์„œ userhistory๋ฅผ ์ถ”๊ฐ€์ ์œผ๋กœ entity ๋ฆด๋ ˆ์ด์…˜์„ ํ™•์ธํ•ด๋ณด์ž.

    void userRelationTest(){
        User user = new User();
        user.setName("david");
        user.setEmail("david@fast.com");
        user.setGender(Gender.MALE);

        userRepository.save(user);

        user.setName("danielll");

        userRepository.save(user);
        user.setEmail("daniel@fast.com");
        userRepository.save(user);

        userHistoryRepository.findAll().forEach(System.out::println);
    }

์ถœ๋ ฅํ•˜๋ฉด.

UserHistory(super=BaseEntity(createdAt=2022-02-08T15:05:10.094, updatedAt=2022-02-08T15:05:10.094), id=1, userId=6, name=david, email=david@fast.com)
UserHistory(super=BaseEntity(createdAt=2022-02-08T15:05:10.141, updatedAt=2022-02-08T15:05:10.141), id=2, userId=6, name=danielll, email=david@fast.com)
UserHistory(super=BaseEntity(createdAt=2022-02-08T15:05:10.141, updatedAt=2022-02-08T15:05:10.141), id=3, userId=6, name=danielll, email=daniel@fast.com)

โœ… ์—ฌ๋Ÿฌ ํžˆ์Šคํ† ๋ฆฌ์ค‘ id๊ฐ’์„ ํŠน์ •ํ•ด์„œ ๋ณผ์ˆ˜ ์žˆ๋„๋ก findByUserId ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค๊ณ  Testํ•ด๋ณด์ž.

public interface UserHistoryRepository extends JpaRepository<UserHistory, Long> {
    List<UserHistory> findByUserId(Long userId);
}
    @Test
    void userRelationTest(){
        User user = new User();
        user.setName("david");
        user.setEmail("david@fast.com");
        user.setGender(Gender.MALE);

        userRepository.save(user);

        user.setName("danielll");
        userRepository.save(user);
        user.setEmail("daniel@fast.com");
        userRepository.save(user);

//        userHistoryRepository.findAll().forEach(System.out::println);
        // Table ๊ด€๊ณ„๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ.
        List<UserHistory> result = userHistoryRepository.findByUserId(userRepository.findByEmail("daniel@fast.com").getId());

        result.forEach(System.out::println);

    }

โœ… ์œ„ ์ฒ˜๋Ÿผ Table ๊ด€๊ณ„๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์™”์ง€๋งŒ Jpa ๊ธฐ๋Šฅ์€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค. JPA์—์„œ ์ œ๊ณตํ•˜๋Š” @OntToMany์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•ด๋ณด์ž.

    @OneToMany
    private List<UserHistory> userHistories
            = new ArrayList<>(); //getUserHistoryes๋ฅผ ํ–ˆ์„๋•Œ NullPointException์ด ๋œจ์ง€ ์•Š๊ฒŒ ๊ธฐ๋ณธ๋ฆฌ์ŠคํŠธ ๋„ฃ์–ด์ฃผ์ž.
    // Jpa์—์„œ ํ•ด๋‹น๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ๋นˆ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ž๋™์œผ๋กœ ๋„ฃ์–ด์ฃผ๊ธฐ๋Š” ํ•˜์ง€๋งŒ, persistํ•˜๊ธฐ ์ „์— ํ•ด๋‹น ๊ฐ’์ด Null์ด๊ธฐ ๋•Œ๋ฌธ์— ๋กœ์ง์— ๋”ฐ๋ผ ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊ธธ์ˆ˜์žˆ๋‹ค.

๊ทธ๋Ÿผ ์œ ์ € Id๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ userHistory๋ฅผ ๋‹ค์‹œ ์กฐํšŒํ•˜๋Š” ๋ถ€๋ถ„์„ ์ˆ˜์ •ํ• ์ˆ˜ ์žˆ๋‹ค.

    @Test
    void userRelationTest(){
        User user = new User();
        user.setName("david");
        user.setEmail("david@fast.com");
        user.setGender(Gender.MALE);

        userRepository.save(user);

        user.setName("danielll");
        userRepository.save(user);
        user.setEmail("daniel@fast.com");
        userRepository.save(user);

//        userHistoryRepository.findAll().forEach(System.out::println);
        // Table ๊ด€๊ณ„๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ.
//        List<UserHistory> result = userHistoryRepository.findByUserId(userRepository.findByEmail("daniel@fast.com").getId());
        List<UserHistory> result = userRepository.findByEmail("daniel@fast.com").getUserHistories();

        result.forEach(System.out::println);

    }

์ด๋ ‡๊ฒŒ ํ•˜๊ณ  Test๋ฅผ ํ•˜๋ฉด LazyInitializationException ์˜ค๋ฅ˜๊ฐ€ ๋‚œ๋‹ค. ํ•˜์ง€๋งŒ ๋‹ค์Œ ์ฑ•ํ„ฐ์—์„œ ๋ฐฐ์šธ ๋‚ด์šฉ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋‹จ, FetchType์„ EAGER๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์ž.

    @OneToMany(fetch = FetchType.EAGER)
    private List<UserHistory> userHistories
            = new ArrayList<>();

@JoinColumn??

์œ„์™€ ๊ฐ™์ด Testํ•˜๊ณ  console(DDL)์„ ํ™•์ธํ•ด๋ณด๋ฉด

    create table user_user_histories (
       user_id bigint not null,
        user_histories_id bigint not null
    )

๐Ÿ˜ˆ user_user_histories๋ผ๋Š” ์ค‘๊ฐ„ ๋งตํ•‘ ํ…Œ์ด๋ธ”์ด ์ƒ์„ฑ๋˜์–ด์žˆ๋‹ค. ์ด๋•Œ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์ด @JoinColume์ด๋‹ค.
@JoinColume์€ Entity๊ฐ€ ์–ด๋–ค ์ปฌ๋Ÿผ์œผ๋กœ joinํ•˜๊ฒŒ ๋ ์ง€ ์ง€์ •ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.

๐Ÿ˜ˆ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด user_user_histories ํ…Œ์ด๋ธ”์€ ์‚ฌ๋ผ์ง€์ง€๋งŒ user_historyํ…Œ์ด๋ธ”์˜ user_id์— Join์ด ๋˜์–ด์•ผํ•˜๋Š”๋ฐ user_histories_id ์ปฌ๋Ÿผ์ด ์ƒˆ๋กœ์ƒ๊ธธ ๊ฒƒ์ด๋‹ค.
๊ทธ๋Ÿฌ๋‹ˆ @JoinColumn(name="user_id")๋ผ๊ณ  ์ง€์ •ํ•ด์„œ user_id๋กœ ์กฐ์ธํ• ๊บผ๋ผ๊ณ  ๋ช…์‹œ์ ์œผ๋กœ ํ‘œํ˜„ํ•ด๋‘ฌ์•ผํ•œ๋‹ค.

๐Ÿ˜ˆ

์ด๋ ‡๊ฒŒ ์˜ค๋ฅ˜๊ฐ€ ๋œจ๋Š”๋ฐ ์ปฌ๋Ÿผ ๋„ค์ž„์ด user_id๋ฅผ ์“ธ์ง€ userId๋กœ ์“ธ์ง€ ๋ชจํ˜ธํ•˜๋‹ค๋Š” ๋œป ์ด๋‹ค.
๊ทธ๋Ÿฌ๋‹ˆ UserHistory์—๋„ ๋ช…์‹œ์ ์œผ๋กœ ํ•ด์ค€๋‹ค.

public class UserHistory extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "user_id")
    private Long userId;

TEST ํ•˜๋ฉด

Hibernate: 

    create table user (
       id bigint generated by default as identity,
        created_at timestamp,
        updated_at timestamp,
        email varchar(255),
        gender varchar(255),
        name varchar(255),
        primary key (id)
    )
Hibernate: 

    create table user_history (
       id bigint generated by default as identity,
        created_at timestamp,
        updated_at timestamp,
        email varchar(255),
        name varchar(255),
        user_id bigint,
        primary key (id)
    )

์œ„์™€๊ฐ™์ด DDL์ด ์žฌ๋Œ€๋กœ ์ƒ์„ฑ๋œ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

UserHistory(super=BaseEntity(createdAt=2022-02-08T15:35:57.741, updatedAt=2022-02-08T15:35:57.741), id=1, userId=6, name=david, email=david@fast.com)
UserHistory(super=BaseEntity(createdAt=2022-02-08T15:35:57.819, updatedAt=2022-02-08T15:35:57.819), id=2, userId=6, name=danielll, email=david@fast.com)
UserHistory(super=BaseEntity(createdAt=2022-02-08T15:35:57.819, updatedAt=2022-02-08T15:35:57.819), id=3, userId=6, name=danielll, email=daniel@fast.com)

๊ฒฐ๊ณผ๋„ ์ž˜ ๋‚˜์˜จ๋‹ค.

insertable, updatable

History๋ผ๋Š” ๊ฐ’์€ User ์—”ํ‹ฐํ‹ฐ์—์„œ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€ํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ์ฆ‰, ReadOnly ์กฐํšŒ์ „์šฉ ๊ฐ’์ด ๋˜์–ด์•ผ ํ•œ๋‹ค.

    @JoinColumn(name = "user_id", insertable = false, updatable = false)

๐Ÿค” ์ดํ›„์— cascade,ํŠธ๋žœ์ ์…˜์—์„œ ๋ฐฐ์šฐ๊ฒ ์ง€๋งŒ..
*๐Ÿค” JPA๋Š” ์ž๋™์œผ๋กœ ๋งŽ์€ ์ฟผ๋ฆฌ๋ฅผ ๋‚˜ ๋Œ€์‹  ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค. ํ•˜์ง€๋งŒ ๋‚˜๋„ ๋ชจ๋ฅด๋Š” ์‚ฌ์ด์— ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ถˆํ•„์š”ํ•œ ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด ์˜ค์ž‘๋™์ด๋‚˜, ์ž ์žฌ์ ์ธ ์„ฑ๋Šฅ ์ด์Šˆ๋ฅผ ๋งŒ๋“ค์ˆ˜ ์žˆ๋‹ค.
Table Entity๋ฅผ ์—ด์‹ฌํžˆ ์„ค๊ณ„ํ•ด์„œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์›ํ•˜๋Š” ์ตœ์ ์˜ ์ฟผ๋ฆฌ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด JPA๊ณ ์ˆ˜์˜ ๊ธธ์ด๋‹ค. ๐Ÿค” *

'Dev > JPA' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

JPA ์—ฐ๊ด€๊ด€๊ณ„ ์‚ดํŽด๋ณด๊ธฐ(1:1)  (0) 2022.03.02
JPA ์—ฐ๊ด€๊ด€๊ณ„ (N:1)  (0) 2022.03.02
JPA EntityListener  (0) 2022.03.02
JPA Entity์˜ ๊ธฐ๋ณธ์†์„ฑ  (0) 2022.03.02
JPA ์ฟผ๋ฆฌ๋ฉ”์†Œ๋“œ ์ •๋ ฌ  (0) 2022.03.02