연관관계(relation) 및 ERD
ERD(앤티티 릴레이션십 다이어그램의 줄임말)
1 . 1 : 1연관관계 - @OneToOn
@OneToOn 어노테이션 옵션 | |
optional | default 값은 true 이다. > outer join false 설정 시 not null로 설정 된다. > inner join |
mappedBy | 연관 키를 해당 테이블에서 가지지 않게 만들어준다. |
🍫 책과 책 리뷰와의 관계
1) 객체 생성
Book , BookReviewInfo 객체 생성
- 필드에 bookId 대신 Book 객체를 넣어줄 수 잇다.
@OneToOn : 1 : 1 연관관계라는 선언.
jpa에서는 entity로 set,get을 하면 릴레이션을 자동으로 맺을 수 있도록 처리해준다.
📑BookReviewInfo
@Entity
@NoArgsConstructor
@Data
public class BookReviewInfo extends BaseEntity{
@Id
@GeneratedValue
private Long id;
// private Long bookId;
@OneToOne
private Book book;
private float averageReviewScore;
private int reviewCount;
}
2) Repository JPA 인터페이스 생성
BookRepository , BookReviewInfoRepository 인터페이스 생성
📑 BookReviewInfoRepository
public interface BookReviewInfoRepository extends JpaRepository<BookReviewInfo,Long>{
}
3) Join 테스트
@Autowired
private BookReviewInfoRepository bookReviewInfoRepository;
@Autowired
private BookRepository bookRepository;
@Test
void crudTest(){
givenBookReviewInfo();
Book result = BookRepository.findById(1L)
.orElseThrow(RuntimeException::new)
.getBook();
System.out.println(result);
}
private Book givenBook(){
Book book = new Book();
book.setName("jap");
book.setAuthorId(1L);
book.setPublisherId(1L);
}
private void givenBookReviewInfo(){
BookReviewInfo bookReviewInfo = new BookReviewInfo();
bookReviewInfo.SetBook(givenBook());
bookReviewInfo.setAverageReviewScore(4.5f);
bookReviewInfo.setReviewCount(2);
bookReviewInfoRepository.save(bookReviewInfo);
System.out.println(bookReviewInfoRepository.findAll());
}
2 . 1 : N 연관관계 - @OneToMany
@OneToMany 어노테이션 옵션 | |
fetch | fetchType.EAGER |
🍫 고객정보와 고객이 변경한 정보 리스트와의 관계
1) 객체 생성
User , UserHistory 객체 생성
- @JoinColumn : entity가 어떤 컬럼으로 조인이 될지 정해주는 어노테이션
@JoinColumn(name="user_id",insertable=false,updatable=false) : user 객체에서 디비 명 설정(설정 하지 않을시 필요 없는 중간 테이블이 생성될 수 있다.) 및 객체 내에서는 해당 필드를 저장 및 수정이 불가능하도록 설정
- user 는 하나이지만 변경 기록은 여러개 일 수 있기 때문에 userHistory 객채를 List로 받는다.
📑User
public class User extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //자동으로 증가
private Long id;
@NonNull
private String name;
@NonNull
private String email;
@Enumerated(value = EnumType.STRING)
private Gender gender;
@OneToMany
@JoinColumn(name="user_id",insertable=false,updatable=false)
private List<UserHistory> userHistories = new ArrayList<>();
}
📑UserHistory
public class UserHistory extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //자동으로 증가
private Long id;
@Column(name="user_id")
private Long userId;
private String name;
private String email;
private Gender gender;
}
2) Join 테스트
- 적용 전 코드
userHistoryRepository.findAll().forEach(System.out::println);
List<UserHistory> result = userHistoryRepository.findByUserId(
userRepository.findByEmail("d@naver.com").getId());
- jpa 어노테이션을 활용시 코드
List<UserHistory> result = userHistoryRepository.findByEmail("d@naver.com").userHistories();
result.forEach(System.out::println);
3 . N : 1 연관관계 - @ManyToOne
4 . M : N 연관관계 - @ManyToMany
( ※ 실제 실무에서는 거이 사용되지 않음 )
ex) 상품 주문 > 상품 , 고객은 ManyToMany 이지만, 주문(Order)라는 중간 테이블을 생성하여 1 : N 형식으로 변경해줄수 있다.
🍫 책과 작가와의 관계
1) 객체 생성
Author , Book 객체 생성
📑author
@Entity
@NOArgsConstructor
@Data
@ToString(callSupper =ture)
@EqualsAndHashCode(callSupper =ture)
public class Author extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String country;
@ManyToMany
@ToString.Exclude
private List<Book> books = new ArrayList<>();
//리스트 생성을 위한 메서드
// ... 배열로 받겠다는 의미
public void addBook(Book... book){
Collections.addAll(this.books, book);
}
}
📑 book ( authores 정보 추가 )
@ManyToMany
@ToString.Exclude
private List<Author> authors = new ArrayList<>();
//리스트 생성을 위한 메서드
public void addAuthor(Author... author){
Collections.addAll(this.authors, author)
}
2) TEST 생성
- @ToString.Exclude : 순환관계에 있는 객체들은 선언을 해줄 필요가 있다.
@SpringBootTest
class AuthorRepositoryTest{
@Autowired
private AuthorRepository authorRepository;
@Autowired
private BookRepository bookRepository;
@Test
@Transactional
void manyToManyTest(){
Book book1 = givenBook("책1");
Book book2 = givenBook("책2");
Book book3 = givenBook("책3");
Book book4 = givenBook("책4");
Author author1 = givenAuthor("작가 1");
Author author2 = givenAuthor("작가 2");
book1.addAuthor(author1);
book2.addAuthor(author2);
book3.addAuthor(author1, author2);
book4.addAuthor(author1, author2);
author1.addBook(book1,book3,book4);
author1.addBook(book2,book3,book4);
bookRepository.saveAll(List.newArrayList(book1,book2,book3,book4));
bookRepository.saveAll(List.newArrayList(author1,author2));
// 세번째 책을 쓴 작가들을 출력
System.out.println("authors through book : " + bookRepository.findAll().get(2).getAuthors());
// 첫번째 작가가 쓴 책들을 출력
System.out.println("books through author : " + authorRepository.findAll().get(0).getBooks());
}
//--- 객체 생성
private Book givenBook(String name){
Book book = new Book();
book.setName(name);
return bookRepository.save(book);
}
private Author givenAuthor(String name){
Author author = new Author();
author.setName(name);
return authorRepository.save(author);
}
}
'BackEnd > Security · JPA' 카테고리의 다른 글
[ JPA ] Transaction (0) | 2023.03.30 |
---|---|
[ JPA ] 영속성 컨텍스트와 Entity 생애주기 (0) | 2023.03.29 |
[ JPA ] @Entity 속성 / Entity Listener /공통으로 사용하는 Entity속성 클래스로 분리하여 재 사용하기 (0) | 2023.03.28 |
[ JPA ] 쿼리메서드 - 페이징 (0) | 2023.03.20 |
[ JPA ] 기본 메서드를 사용한 쿼리 - CRUD · Page (0) | 2023.03.16 |