SpringBoot/day57 / 23.11.27(월) / (핀테크) Spring 및 Ai 기반 핀테크 프로젝트 구축

허니몬·2023년 11월 27일
0
post-thumbnail

P07_data_jpa

# Repository 인터페이스
- 기존의 DAO(Data Access Object) 와 동일한 개념
- 비즈니스 클래스에서는 Repository 를 이용하여 실질적인 데이터베이스 연동을 처리
# 쿼리 메서드
- JPA 를 이용해서 목록 기능을 구현할 때에는 
  JPQL( Java Persistence Query Language ) 를 이용
- JPQL 은 검색 대상이 테이블이 아닌 엔티티라는 것만 제외하면 
  기본 구조와 문법이 기존의 SLQ과 유사  
- JPA 에서는 복잡한 JPQL 을 메서드로 처리할 수 있도록 '쿼리 메서드'라는 특별한 기능을 제공 
- 쿼리 메서드를 이요할 때 가장 많이 사용하는 문법은 검색하려는 엔티티에서 특정 변수의 값만 조회하는 것
  메서드 이름을 find 로 시작하면서 조회할 변수들을 적절하게 조합하면 됨
  > find + 엔티티 이름 + By + 변수 이름(첫 글자 대문자) > camel 표기법
  Ex) findBoardByTitle() : Board 엔티티에서 title 변수 값만 조회
- 쿼리 메서드를 작성할 때 엔티티 이름은 생략할 수 있다
  이름이 생략되면 현재 사용하는 Repository 인터페이스에 선언된
  타입 정보를 기준으로 엔티티 이름이 자동 적용
  > public interface Repository extends CrudRepository<Board, Long> : 여기서 Board
    find + By + 변수 이름

# 복잡한 쿼리를 작성하는 경우나 연관관계에 기반한 조인검색을 처리하기 위해서는 JPQL 을 사용
  특정 데이터베이스에 종속적인 네이티브 쿼리를 사용해야 하는 경우에는,
  @Query 을 적용


# QueryDSL
- JPA 에서는 @Query 를 이용해서 application 에서 사용할 쿼리를 관리
  @Query 로 등록한 쿼리는 프로젝트가 로딩되는 시점에 파싱되기 때문에 고정된 SQL만 사용할 수 있다
  Mybatis 처럼 동적으로 쿼리를 처리하려면 QueryDSL(Query Domain Specific Language ) 

	board-mapping.xml
	   
	   <select id="getBoardList" resultMap="boardResult">
	      SELECT *
	      FROM BOARD
	      WHERE 1 = 1 
	      <if test="searchCondition == 'TITLE' ">
	         AND TITLE LIKE '%'||#{searchKeyword}||'%'
	      </if>
	      <if test="searchCondition == 'CONTENT'>
	         AND CONTENT LIKE '%'||#{searchKeyword}||'%'
	      </if>
	      ORDER BY SEQ DESC
	   </select>

1. QueryDSL 설정
- QueryDSL 관련 라이브러리 추가
  https://mvnrepository.com 접속 > querydsl 검색
  > Querydsl JPA : QueryDSL JPA 라이브러리
    Query APT	 : 쿼리 타입(Q)를 생성할 때 필요한 라이브러리
    
------------------------------------------------------------------------------------------------
pom.xml 에 추가
<!-- https://mvnrepository.com/artifact/com.querydsl/querydsl-jpa -->
<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-jpa</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.querydsl/querydsl-apt -->
<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-apt</artifactId>
</dependency>
------------------------------------------------------------------------------------------------
2. QueryDSL Plugin 추가
- QueryDSL 을 사용하려면 엔티티 클래스 기반으로 쿼리 타입이라는 쿼리용 클래스를 생성해야 한다
  > pom.xml 파일에서 우클릭 -> [Maven]-[Add Plugin] 선택
    Group Id	: com.mysema.maven 
	Artifact Id	: apt-maven-plugin
	Version		: 1.1.3
      <plugin>
         <groupId>com.mysema.maven</groupId>
         <artifactId>apt-maven-plugin</artifactId>
         <version>1.1.3</version>
         <executions><!-- 만약 에러가 발생한다면 eclipse.ini에 –vm 옵션 설정을 하면 된다.-->
            <execution>
               <goals>
                  <goal>process</goal>
               </goals>
               <configuration><!--경로설정은 자신의 경로에 맞게-->
                  <outputDirectory>src/main/querydsl</outputDirectory>
                  <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
               </configuration>
            </execution>
         </executions>
      </plugin>


# 연관관계 매핑
- 관계형 데이터베이스에서 테이블 하나로 애플리케이션에서 사용하는 모든 데이터를 관리하는 것은 불가능 하다
  따라서 관련된 데이터를 여러 테이블에 나누어 저장하고 테이블을 조인하여 데이터 처리
  
- 테이블이 관계를 맺듯이 엔티티 역시 다른 엔티티와 관계를 맺고 있으며
  이 관계를 통해 데이터를 관리할 수 있다.
- 테이블은 PK 와 FK 를 기반으로 연관 관계를 맺지만, 
  객체는 참조 변수를 통해 연관관계를 맺기 때문에,
  테이블의 연관과 엔티티의 연관이 정확하게 일치하지 않는다.  
Ex) 어떤 회원이 탈퇴를 했을 때 그 회원이 작성한 게시글 까지 같이 사라짐



main///


Board

package com.web.domain;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString(exclude = "boardList")
@Entity
@Table(name = "MYBOARD")
public class Board {
	@Id
	@GeneratedValue
	private Long seq;
	private String title;
//  private String writer;
	private String content;
	@Temporal(TemporalType.TIMESTAMP)
	private Date createDate;
	private Long cnt;
	// ------------------------------------------------------------------------------
	// Member 생성 이후
	@ManyToOne					 	// 다대일(N:1) 관계 설정       내부 조인 nullable  속성 쓰지 않을 때
	@JoinColumn(name = "MEMBER_ID", nullable = false) // FK Join : 외부 조인 nullable를 false로 하면 내부조인 됨
	private Member member;			// Member 객체와 연관관계 매핑
	
	// 게시판 객체에 회원 객체를 설정할 때 회원이 소유한 게시글 컬렉션에 자신(게시글)도 자동 저장
	public void setMember(Member member) {
		this.member = member;
		member.getBoardList().add(this);
	}
	
}

Member

package com.web.domain;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString(exclude = "member")
@Entity
@Table(name = "MYUSER")
public class Member {
	@Id
	@Column(name = "MEMBER_ID")
	private String id;
	private String password;
	private String name;
	private String role;
	
	
	// # mappedBy
	// - 양방향 연관관계에서 연관관계의 주인을 지정할 때 사용
	// - 연관관계 주인 테이블에 FK가 있는 곳으로 지정
	// # fetch
	// - 회원 정보를 조회할 때 연관관계에 있는 게시판 정보도 같이 조회할 것인지를 결정
	// - fetch 속성의 기본값을 LAZY
	// - EAGER 로 설정하면 회원정보를 가져올 때 회원이 등록한 게시글 목록도 같이 조회
//	@OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
	
	// # 영속성 전이
	// - CascadeType.All 을 적용하면, 회원 객체가 영속되거나 수정 또는 삭제 될 때
	// 회원과 관련된 게시판도 같이 변경 또는 삭제
	@OneToMany(mappedBy = "member", fetch=FetchType.EAGER, cascade=CascadeType.ALL)	
	private List<Board> boardList = new ArrayList<>();
}


persistence..


Repository

package com.web.persistence;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;

import com.web.domain.Board;

/*
 * # CurdRepository
 * - 기본적인 CRUD 기능을 제공
 * - CurdRepository<T, ID>
 *   > T	: 엔티티 클래스 타입
 *     ID	: 식별자 타입(@Id 로 매핑한 식별자 변수의 타입)
 *     
 * # 스프링 데이터 JPA 를 사용하는 경우 별도의 구현 클래스를 만들지 않고
 *   인터페이스만 정의함으로써 기능을 사용할 수 있다
 *   스프링 부트가 내부적으로 인터페이스에 대한 구현 객체를 자동으로 생성해 줌
 */

public interface Repository extends CrudRepository<Board, Long>{
//	// 쿼리 메서드
//	List<Board> findByTitle(String searchKeyword);
//	// 포함된 글자
//	List<Board> findByContentContaining(String searchKeyword);
//	// OR 
//	List<Board> findByTitleContainingOrContentContaining(String title, String content);
//	// 정렬
//	List<Board> findByTitleContainingOrderBySeqDesc(String searchKeyword);
//	// 페이징과 정렬 처리
//	// import org.springframework.data.domain.Pageable;
////	List<Board> findByTitleContaining(String searchKeyword, Pageable paging);
//	// Page<T> 타입 사용
//	Page<Board> findByTitleContaining(String searchKeyword, Pageable paging);
}

Repository2

package com.web.persistence;

import java.util.List;

import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;

import com.web.domain.Board;
/*
 * # @Query
 * - JQPL 사용시 검색대상은 테이블이 아니라 엔티티
 */
public interface Repository2 extends CrudRepository<Board, Long>{
//	// 위치 기반 파라미터
//	// - WHERE 절에 LIKE 연산자를 사용하고, 사용자 입력 값이 '?1' 에 바인딩 되어 검색
//	// 엔티티(클래스) 이름과 table 자리에 들어가는 이름이 같아야 함
//	@Query("SELECT b FROM Board b WHERE b.title LIKE %?1% ORDER BY b.seq DESC")
//	List<Board> queryAnnotationTest(String searchKeyword); // 매개변수가 쿼리문의 ? 으로 들어감
//	
//	// 이름 기반 파라미터
//	// - ":searchKeyword" 파라미터에 매개변수로 받은 searchKeyword 값이 바인딩 되도록
//	//   @Param 을 사용
//	@Query("SELECT b FROM Board b WHERE b.title LIKE %:searchKeyword% ORDER BY b.seq DESC")
//	List<Board> queryAnnotationTest2(@Param("searchKeyword") String searchKeyword);
//	
//	// 특정 변수만 조회
//	// - 특정 변수 값만 조회할 때 검색결과로 엔티티 객체로 조회되는 것이 아니라
//	//   여러 변수 값들이 조회됨
//	//   >> findByTitle() 메서드의 리턴 타입을 'List<Object[]>' 로 해야 함
//	@Query("SELECT b.seq, b.title, b.writer, b.createDate "
//		 + "FROM Board b WHERE b.title LIKE %?1%"
//		 + "ORDER BY b.seq DESC")
//	List<Object[]> queryAnnotationTest3(String searchKeyword);
//	
//	// 네이티브 쿼리 사용
//	// 네이티브 쿼리는 일반 쿼리문이므로 테이블 이름 자리에 엔티티 이름과 맞출 필요가 없다
//	// 하지만 @Query 속성으로 nativeQuery = true 써줘야 함
//	// - 네이티브 쿼리를 사용하면 특정 데이터 베이스에 종속되는 문제가 있지만
//	//   성능상 특정 데이터베이스에 최적화된 쿼리를 사용해야 하는 경우에 유용하다
//	// - 쿼리문이 JPQL 이 아닌 nativeQuery임을 알려주는 것이 'nativeQuery = true' 이다
//	@Query(value = "SELECT seq, title, writer, create_Date "
//				 + "FROM board WHERE title LIKE '%'||?1||'%' "
//				 + "ORDER BY seq DESC", nativeQuery = true)
//	List<Object[]> queryAnnotationTest4(String searchKeyword);
//	
//	// 페이징 및 정렬 처리하기
//	// - @Query 를 사용하더라도 페이징 처리를 위한 Pageable 인터페이스는 
//	//   쿼리 메서드와 동일하게 사용할 수 있다
//	//   Sort 를 이용하여 조회 결과에 대해서 정렬도 추가할 수 있다.
//	@Query("SELECT b FROM Board b ORDER BY b.seq DESC")
//	List<Board> queryAnnotationTest5(Pageable paging);

	
	
	
}

DynamicRepository

package com.web.persistence;

import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.CrudRepository;

import com.web.domain.Board;

public interface DynamicRepository extends CrudRepository<Board, Long>, QuerydslPredicateExecutor<Board>{
}

MemberRepository

package com.web.persistence;

import org.springframework.data.repository.CrudRepository;

import com.web.domain.Member;

public interface MemberRepository extends CrudRepository<Member, String>{
}


test///


BoardRepositoryTest

package com.web;

import java.util.Date;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.web.domain.Board;
import com.web.persistence.Repository;

/*
 * # 엔티티를 영속성 컨텍스트에 저장하기 위해서 JPA 의 persist() 메서드를 사용하지만,
 *   CrudRepository 인터페이스를 사용할 때에는 save() 메서드를 사용한다.
 * 
 */
@SpringBootTest
public class BoardRepositoryTest {
	@Autowired
	private Repository boardRepo;
	
	// 등록 테스트
		@Test
		public void testInsertBoard() {
			Board board = new Board();
			board.setTitle("두 글");
			board.setWriter("user2");
			board.setContent("등록 테스트");
			board.setCreateDate(new Date());
			board.setCnt(0L);
			
			boardRepo.save(board);
		}
		
		//----------------------------------------------------------------------
		
		// 조회 테스트
		@Test
		public void testGetBoard() {
			Board board = boardRepo.findById(1L).get();
			System.out.println("---> " + board.toString());
		}
		
		//----------------------------------------------------------------------
		
		// 수정 테스트
		@Test
		public void testUpdateBoard() {
			System.out.println("- 1번 게시글 조회 -");
			Board board = boardRepo.findById(2L).get();
			System.out.println("1번 글 수정");
			board.setWriter("작가 수정");
			board.setContent("내용 수정");
			board.setTitle("제목 수정");
			
			boardRepo.save(board);
			// 수정된 내용 확인
			System.out.println("---> " + board.toString());
		}
		//----------------------------------------------------------------------
		
		// 삭제 테스트
		@Test
		public void deleteBoard() {
			boardRepo.deleteById(2L);
		}
		
		@Test
		public void testGetBoard() {
			Board board = boardRepo.findById(1L).get();
			System.out.println("---> " + board.toString());
		}
	
}

DynamicQueryTest

package com.web;

import java.util.Date;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import com.querydsl.core.BooleanBuilder;
import com.web.domain.Board;
import com.web.domain.QBoard;
import com.web.persistence.DynamicRepository;
import com.web.persistence.Repository;
import com.web.persistence.Repository2;

@SpringBootTest
public class DynamicQueryTest {

	@Autowired
	private DynamicRepository dr;

	@Autowired
	private Repository br;
	
	@BeforeEach
	public void dataPrepare() {
		for(int i=0; i<200; i++) {
			Board board = new Board();
			board.setTitle("테스트 제목 " + i);
			board.setWriter("user"+ i);
			board.setContent(i+" 번째 내용");
			board.setCreateDate(new Date());
			board.setCnt(0L);
			br.save(board);
		}
	}
	@Test
	public void testDynamicQuery() {
		// 검색 조건
		String searchCondition = "content";
		String searchKeyword = "1 번";
		
		// com.querydsl.core.BooleanBuilder 객체 이용하면 가변적인 파라미터 값에
		// 동적으로 And 나 OR 에 해당하는 조건을 추가할 수 있다.
		BooleanBuilder builder = new BooleanBuilder();
		QBoard qBoard = QBoard.board;
		if(searchCondition.equals("TITLE")) {
			builder.and(qBoard.title.like("%" + searchKeyword + "%"));
		} else if(searchCondition.equals("content")) {
			builder.and(qBoard.content.like("%" + searchKeyword + "%"));
		}
		
		// 페이징 처리
		Pageable paging = PageRequest.of(0, 5);
		
		Page<Board> list = dr.findAll(builder, paging);
		
		System.out.println("- 검색 결과 -");
		for(Board board : list) {
			System.out.println("---> " + board.toString());
		}
	}
}

QueryMethodTest

package com.web;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import com.web.domain.Board;
import com.web.persistence.Repository;


@SpringBootTest
public class QueryMethodTest {
	@Autowired
	private Repository boardRepo;
	
	// 쿼리 메서드 테스트용 데이터
	
	@BeforeEach
	public void dataPrepare() {
		for(int i=0; i<200; i++) {
			Board board = new Board();
			board.setTitle("테스트 제목 " + i);
			board.setWriter("user"+ i);
			board.setContent(i+" 번째 내용");
			board.setCreateDate(new Date());
			board.setCnt(0L);
			boardRepo.save(board);
		}
	}
	
	// 쿼리 메서드
	@Test
	public void findByTitle() {
		List<Board> list = new ArrayList<>();
		list = boardRepo.findByTitle("테스트 제목 1");
		System.out.println("- 검색 결과 -");
		for(Board board : list) {
			System.out.println("---> "+ board.toString());
		}
	}
	
	// LIKE 연산자 사용
	// - 특정 단어가 포함된 목록을 검색하려면 Like 연산자와 Containing 키워드를 사용
	@Test
	public void findByContentContaining() {
		List<Board> list = boardRepo.findByContentContaining("10");
		System.out.println("- 검색 결과2 포함 -");
		for(Board board : list) {
			System.out.println("---> "+ board.toString());
		}
	}
	// 여러 조건 사용
	// - 제목 혹은 내용에 들어가는 검색어가 동일하더라도 하나의 변수로 처리할 수 없음
	// 즉, 원하는 검색값에 대한 매개변수를 다 넣어 줘야 함
	@Test
	public void findByTitleContainingOrContentContaining() {
		List<Board> list = boardRepo.findByTitleContainingOrContentContaining("10", "10");
		System.out.println("- 검색 결과3 포함, OR -");
		for(Board board : list) {
			System.out.println("---> "+ board.toString());
		}
		
	}
	// 데이터 정렬
	// - 데이터를 정렬 해서 조회할 때에는 'OrderBy' + 변수 + 'Asc or Desc' 사용
	@Test
	public void findByTitleContainingOrderBySeqDesc() {
		List<Board> list = boardRepo.findByTitleContainingOrderBySeqDesc("10");
		System.out.println("- 검색 결과4 정렬 -");
		for(Board board : list) {
			System.out.println("---> "+ board.toString());
		}
	}
	
	// 페이징과 정렬 처리
	// - 모든 쿼리 메서드는 마지막 파라미터로 페이징 처리를 위한 Pageable 인터페이스와
	//   정렬을 처리하는 Sort 인터페이스를 추가할 수 있다.
	@Test
	public void findByTitleContaining() {
		// - 첫 번쨰 인자 0 은 페이지 번호.
		//   0 부터 시작하기 때문에 첫번째 페이지를 보고 싶으면 0 으로 설정
		// - 두 번째 인자인 5는 검색할 데이터의 갯수
		// - 페이징을 처리할 때 데이터를 정렬해서 출력하려면 Sort 클래스를 사용 
		
		Pageable pageable = PageRequest.of(1, 5); // >> 0번째 페이지에서 5개
		Pageable pageable = PageRequest.of(1, 5, Sort.Direction.DESC,"seq");
		List<Board> list = boardRepo.findByTitleContaining("10", pageable);
		System.out.println("- 검색 결과5 정렬과 페이징(List) -");
		for(Board board : list) {
			System.out.println("---> "+ board.toString());
		}
	}
	@Test
	public void findByTitleContaining() {
		Pageable pageable = PageRequest.of(1, 5, Sort.Direction.DESC,"seq");
		Page<Board> pageInfo = boardRepo.findByTitleContaining("10", pageable);
		
		System.out.println("- 검색 결과6 정렬과 페이징 Page<T> -");
		System.out.println("PAGE SIZE : " + pageInfo.getSize());
		System.out.println("TOTAL PAGES : " + pageInfo.getTotalPages());
		System.out.println("TOTAL COUNT : " + pageInfo.getTotalElements());
		System.out.println("NEXT : " + pageInfo.nextPageable());
		
		List<Board> list = pageInfo.getContent();
		
		for(Board board : list) {
			System.out.println("---> "+ board.toString());
		}
	}
}

QueryAnnotationTest

package com.web;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import com.web.domain.Board;
import com.web.persistence.Repository2;

@SpringBootTest
public class QueryAnnotationTest {
	
	@Autowired
	private Repository2 br;
	
	@BeforeEach
	public void dataPrepare() {
		for(int i=0; i<200; i++) {
			Board board = new Board();
			board.setTitle("테스트 제목 " + i);
			board.setWriter("user"+ i);
			board.setContent(i+" 번째 내용");
			board.setCreateDate(new Date());
			board.setCnt(0L);
			br.save(board);
		}
	}
	
	@Test
	public void testQueryAnnotationTest() {
		List<Board> list = br.queryAnnotationTest("테스트 제목 10");
		System.out.println("- 검색 결과 -");
		for(Board board : list) {
			System.out.println("-----> " + board.toString());
		}
	}
	@Test
	public void testQueryAnnotationTest2() {
		List<Board> list = br.queryAnnotationTest("테스트 제목 10");
		System.out.println("- 검색 결과2 -");
		for(Board board : list) {
			System.out.println("-----> " + board.toString());
		}
	}
	@Test
	public void testQueryAnnotationTest3() {
		List<Object[]> list = br.queryAnnotationTest3("테스트 제목 10");
		System.out.println("- 검색 결과3 특정 변수 검색 -");
		for(Object[] row : list) {
			System.out.println("-----> " + Arrays.toString(row));
		}
	}
	@Test
	public void testQueryAnnotationTest4() {
		List<Object[]> list = br.queryAnnotationTest4("테스트 제목 10");
		System.out.println("- 검색 결과4 nativeQuery -");
		for(Object[] row : list) {
			System.out.println("-----> " + Arrays.toString(row));
		}
	}
	@Test
	public void testQueryAnnotationTest5() {
		
		Pageable paging = PageRequest.of(0, 3, Sort.Direction.DESC, "seq");
		
		List<Board> list = br.queryAnnotationTest5(paging); 
		System.out.println("- 검색 결과4 nativeQuery -");
		for(Board board : list) {
			System.out.println("-----> " + board.toString());
		}
	}
}

RelationMappingTest

package com.web;

import java.util.Date;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.web.domain.Board;
import com.web.domain.Member;
import com.web.persistence.MemberRepository;
import com.web.persistence.Repository;

@SpringBootTest
public class RelationMappingTest {
	@Autowired
	private Repository boardRepo;
	@Autowired
	private MemberRepository memberRepo;
	
	
	// 다대일 연관관계 테스트 : 게시글 등록
	@Test
	public void testManyToOneInsert() {
		Member member1 = new Member();
		member1.setId("member1");
		member1.setPassword("123");
		member1.setName("name1");
		member1.setRole("User");
		memberRepo.save(member1);
		
		Member member2 = new Member();
		member2.setId("member2");
		member2.setPassword("123");
		member2.setName("name2");
		member2.setRole("Admin");
		memberRepo.save(member2);
		
		for(int i=0; i<=3; i++) {
			Board board = new Board();
			board.setMember(member1);
			board.setTitle("회원_1 이(가) 등록한 게시글"+i);
			board.setContent("회원_1 이(가) 등록한 게시글 내용"+i);
			board.setCreateDate(new Date());
			board.setCnt(0L);
			boardRepo.save(board);
		}
		for(int i=0; i<=3; i++) {
			Board board = new Board();
			board.setMember(member2);
			board.setTitle("회원_2 이(가) 등록한 게시글"+i);
			board.setContent("회원_2 이(가) 등록한 게시글 내용"+i);
			board.setCreateDate(new Date());
			board.setCnt(0L);
			boardRepo.save(board);
		}
	}
	
	@Test
	public void testManyToOneSelect() {
		Board board = boardRepo.findById(5L).get();
		System.out.println("[ " + board.getSeq() + " 번 게시글 정보 ]");
		System.out.println("제목 : " + board.getTitle());
		System.out.println("내용 : " + board.getContent());
		System.out.println("작성자 : " + board.getMember().getName());
		System.out.println("작성자 권한 : " + board.getMember().getRole());
	}
	// 참조키에 값이 항상 설정된다면, 내부 조인으로 변경함
	// @JoingColumn 에 nullable 속성
	// - Member.member 변수와 매핑되는 MEMBER_ID 컬럼이 항상 참조로 값을 가진다는 의미
	
	// 영속성 전이
	@Test
	public void testManyToOneInsert() {
		Member member1 = new Member();
		member1.setId("member1");
		member1.setPassword("123");
		member1.setName("name1");
		member1.setRole("User");
//		memberRepo.save(member1);
		
		Member member2 = new Member();
		member2.setId("member2");
		member2.setPassword("123");
		member2.setName("name2");
		member2.setRole("Admin");
//		memberRepo.save(member2);
		
		for(int i=0; i<=3; i++) {
			Board board = new Board();
			board.setMember(member1);
			board.setTitle("회원_1 이(가) 등록한 게시글"+i);
			board.setContent("회원_1 이(가) 등록한 게시글 내용"+i);
			board.setCreateDate(new Date());
			board.setCnt(0L);
//			boardRepo.save(board);
		}
		memberRepo.save(member1);
		
		for(int i=0; i<=3; i++) {
			Board board = new Board();
			board.setMember(member2);
			board.setTitle("회원_2 이(가) 등록한 게시글"+i);
			board.setContent("회원_2 이(가) 등록한 게시글 내용"+i);
			board.setCreateDate(new Date());
			board.setCnt(0L);
//			boardRepo.save(board);
		}
		memberRepo.save(member2);
	}
	
	// 삭제
	@Test
	public void testCascadeDelete() {
		memberRepo.deleteById("member2");
	}
	
}
profile
Fintech

0개의 댓글