Jpa

JPA @OneToOne 매핑이 안된다고? Unique

lee-maru 2020. 11. 4. 09:24

JPA @OneToOne 매핑이 안된다고?

Introduction

JPA를 사용하면서 @OneToOne 어노테이션을 많이 보고 사용했을 것이다. 이 글에서는 OneToOne 어노테이션을 사용했는데도, 데이터가 한개가 아닌 2개가 들어가서 @OneToMany로 들어가는 일이 있거나, 그런 궁금증을 가지신 분들이 보면 도움이 될 수 있다고 생각한다.

* 이 글은 JPA,, Database 사전지식이 있다는 가정하에 서술하였습니다.

* 환경(Intelli j, h2 database)

Situation

1. 두개의 1대1 양방향 관계의 엔티티가 있습니다. (Son, Parent)

@Entity

@Table

public class Son {

   @Id

   @Column

   private String name;


   @Column

   Integer age;


   @JoinColumn

   @OneToOne

   private  Parent parent;

}

2. 각자의 엔티티를 사용해서, Son 객체 2개를 생성해서 똑같은 부모 Foreign키를 사용해보겠습니다.

@Entity

@Table

public class Parent {

   @Id

   @Column

   private String name;


   @Column

   private Integer age;


   @OneToOne(mappedBy = "parent")

   @JoinColumn

   private Son son;

}

3. 구동결과

```java
public class FamilyService {

public static void main(String[] args) {

   EntityManagerFactory emf =  Persistence.createEntityManagerFactory("hello");


   EntityManager em = emf.createEntityManager();


   EntityTransaction tx = em.getTransaction();

   tx.begin();


   Parent parent = new Parent();

   parent.setName("엄마");


   Son son1 = new Son();

   Son son2 = new Son();


   son1.setName("아들1");

   son1.setAge(11);

   son1.setParent(parent);

   parent.setSon(son1);


   son2.setName("아들2");

   son2.setAge(10);

   son2.setParent(parent);


   em.persist(parent);

   em.persist(son1);

   em.persist(son2);

   tx.commit();



   em.close();

   emf.close();

}

}

  • 이상하게 너무 잘돌아간다. (아들1과 아들2는 알고보니 형제였던거임)

  • Hibernate 를 보면 OneToOne 을 비웃기라도 한듯이 너무 잘들어 간다.

사실 정상적인 구동 결과이다. DB자체에다가, 물리적으로 제약을 걸어준 것도 아니고, 자바입장에서도 객체 레퍼런스값을 집어넣는데 문제가 생길 이유도 명분도 없다.

근데 이왕 어노테이션 까지 붙였으면 Hibernate 가 영속성 컨텍스트나 1차캐시 안에서 무언가 해줄거라고 생각했던 내 착각이었다.

결론적으로 ORM에서 말하는 1:1 , 1:N 관계라는 것은 관계형 데이터베이스 기준의 관계이다.

특히 1:1 같은 경우에는 필요에 따라 적절하게 제약조건을 걸어줘야 한다.

  • DB 에다가 물리적으로 걸어줘야하나?

(그냥 디비에다가 걸어주면 되고)

  • 아니면 Hibernate 에서 해결할 방법이 있을까?

보면 알듯이 조인컬럼에다가 unique 제약 조건이 걸 수 있는데, 친절한건지 unique가 false가 되어있다.

이걸 True로 바꿔주고 다시 기동해보면

객체에 참조값 다 들어가고 persist 하기전 트렌젝션 커밋에서 바로 unique 제약조건 걸려서 오류가 뜬다.

Service에 Exception을 해야했는데 귀찮아서 안했지만 아마 Exception 띄우고 진행하면 rollback 이 될거다.