JPA

brave_chicken·2024년 6월 18일

잇(IT)생 챌린지

목록 보기
73/90

양방향관계에서 여러데이터 삽입,조회

DeptEntity

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "mydept")
public class DeptEntity {
    @Id
    @GeneratedValue
    @Column(name = "deptNo")
    private Long id;
    private String name;
    private String mgr;
    //양방향관계에서는 항상 기준이 되는 엔티티는 외래키 테이블을 표현한 엔티티
    //현테이블과 매핑되는 테이블이 엔티티에서 어떤 컬럼명으로 명시되어 있는지 정의
    //양방향에서는 mappedBy 속성을 이용해서 내가 뭐에 의해서 매핑이 됐는지 명시
    //상대엔티티에서 현 엔티티를 매핑하고 있는 변수명을 정의
    //mappedBy가 정의되어있는 엔티티에서는 조회만 가능하도록 처리
    @OneToMany(mappedBy = "dept")
    //양방향참조에서 toString을 호출하면 순환참조오류가 발생한다.
    //dept에서 emp의 toString을 호출하고 emp에서 dept의 toString을 호출한다.
    //직접호출하지않아도 JSON객체를 만들때 내부에서 toString을 호출하는 상황이 만들어진다.
    @ToString.Exclude //toString메소드에 해당컬럼을 포함하지 않겠다는 의미
    private List<EmpEntity> emplist = new ArrayList<>();

    public DeptEntity(String name, String mgr) {
        this.name = name;
        this.mgr = mgr;
    }
}

EmpEntity

//단방향으로 작업
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "myemp")
public class EmpEntity extends PublicInfoEntity {
    @Id
    private String userId;
    private String name;
    private String addr;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "userPrivateId")
    private PrivateInfoEntity infoEntity;


    public EmpEntity(String userId, String name, String addr, PrivateInfoEntity infoEntity) {
        this.userId = userId;
        this.name = name;
        this.addr = addr;
        this.infoEntity = infoEntity;
    }

    //경력사항은 한 사람이 여러 개 가질 수 있다.
    @OneToMany(mappedBy = "emp", cascade = CascadeType.ALL)
//    @JoinColumn(name = "userKey")
    private List<HistoryEntity> historylist = new ArrayList<>();

    @ManyToOne
    @JoinColumn(name = "deptId")
    private DeptEntity dept;

    //양방향관계에서 주데이터 이외의 새로 추가된 데이터가 반영된다.
    public void changeVal(HistoryEntity history){
        historylist.add(history);
        history.setEmp(this);
    }

    //모든정보를 Emp에 저장하기
    //양방향관계에서 기본객체가 아닌 객체도 데이터가 반영될 수 있도록 처리하기
    public static EmpEntity buildEmpEntity(String userId, String name, String addr,
                                           PrivateInfoEntity infoEntity, List<HistoryEntity> historylist, DeptEntity dept){
        EmpEntity entity = new EmpEntity(userId,name,addr,infoEntity,dept);
        //historylist에서 history를 꺼내서 emp를 셋팅
        for (HistoryEntity history:historylist){
            entity.changeVal(history);
        }
        return entity;
    }

    public EmpEntity(String userId, String name, String addr, PrivateInfoEntity infoEntity, List<HistoryEntity> historylist) {
        this.userId = userId;
        this.name = name;
        this.addr = addr;
        this.infoEntity = infoEntity;
        this.historylist = historylist;
    }

    public EmpEntity(String userId, String name, String addr, PrivateInfoEntity infoEntity, DeptEntity dept) {
        this.userId = userId;
        this.name = name;
        this.addr = addr;
        this.infoEntity = infoEntity;
        this.dept = dept;
    }
}

HistoryEntity

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "myhistory")
public class HistoryEntity {
    @Id
    @GeneratedValue
    private Long historyId;
    private String company;
    private String content;

    @ManyToOne
    @JoinColumn(name = "id")
    private EmpEntity emp;

    public HistoryEntity(String company, String content) {
        this.company = company;
        this.content = content;
    }
}

JPAWayTest

@SpringBootTest
@Transactional
@Rollback(value = false)
class JPAWayTest {
    @PersistenceContext
    EntityManager entityManager;

    @Test
    public void test1() {
        //초기데이터 저장하기
        DeptEntity dept1 = new DeptEntity("전산실", "RM");
        DeptEntity dept2 = new DeptEntity("인사팀", "슈가");
        DeptEntity dept3 = new DeptEntity("기획실", "뷔");

        entityManager.persist(dept1);
        entityManager.persist(dept2);
        entityManager.persist(dept3);
        //사원을 등록할 때 경력 사항을 같이 등록하기
        //파라미터로 전달 받은 부서 코드를 이용해서 부서 정보 조회
        PrivateInfoEntity privateInfo1 =
                new PrivateInfoEntity("bts1", "태양과 듀엣", "솔로");
        PrivateInfoEntity privateInfo2 =
                new PrivateInfoEntity("bts2", "Seven", "올림픽곡");
        PrivateInfoEntity privateInfo3 =
                new PrivateInfoEntity("bts3", "춤모야", "조교");
        PrivateInfoEntity privateInfo4 =
                new PrivateInfoEntity("bts4", "제대했다", "너무해");
        PrivateInfoEntity privateInfo5 =
                new PrivateInfoEntity("kbr", "싱어송라이터", "바람바람바람");

        //경력사항 3개
        List<HistoryEntity> historyEntityList = new ArrayList<>();
        historyEntityList.add(new HistoryEntity("A사", "front개발"));
        historyEntityList.add(new HistoryEntity("B사", "Entity개발"));
        historyEntityList.add(new HistoryEntity("C사", "보안"));


        EmpEntity emp1 = new EmpEntity("bts1", "지민", "광주"
                , privateInfo1, historyEntityList, dept1);
        EmpEntity emp2 = new EmpEntity("bts2", "정국", "부산", privateInfo2, dept1);
        EmpEntity emp3 = new EmpEntity("bts3", "제이홉", "광주", privateInfo3, dept2);
        EmpEntity emp4 = new EmpEntity("bts4", "석진", "천안", privateInfo4, dept2);
        EmpEntity emp5 = new EmpEntity("kbr", "범룡", "청주", privateInfo5, dept3);

        entityManager.persist(emp1);
        entityManager.persist(emp2);
        entityManager.persist(emp3);
        entityManager.persist(emp4);
        entityManager.persist(emp5);

    }

    @Test
    public void test2() {
        //dept데이터 조회하기 : Dept -> Emp
        //ctrl+alt+L
        //1번부서
        DeptEntity deptEntity = entityManager.find(DeptEntity.class, 1L);
        System.out.println(deptEntity);

        //양방향은 양쪽의 모든 엔티티에서 각자방향으로 객체를 접근할 수 있다.
        List<EmpEntity> emplist = deptEntity.getEmplist();
        for (EmpEntity emp : emplist) {
            System.out.println(emp + "=>" + emp.getDept());
        }
    }

    @Test
    public void test3() {
        //emp조회 : Emp -> Dept
        EmpEntity empEntity = entityManager.find(EmpEntity.class, "bts1");
        System.out.println(empEntity);
        System.out.println(empEntity.getDept().getName());
    }

    @Test
    public void test4() {
        //새로운 사원을 등록
        DeptEntity dept = entityManager.find(DeptEntity.class, "2");
        System.out.println(dept);
        List<HistoryEntity> historyEntityList = new ArrayList<>();

        historyEntityList.add(new HistoryEntity("D사", "front react개발"));
        historyEntityList.add(new HistoryEntity("E사", "Entity개발"));
        historyEntityList.add(new HistoryEntity("A사", "보안개발"));

        EmpEntity emp = new EmpEntity("bts7", " 슈가", "대구",
                new PrivateInfoEntity("bts7", "화양연화", "래퍼"),
                historyEntityList, dept);
        entityManager.persist(emp);
    }

    @Test
    public void test5() {
        //새로 삽입된 데이터를 조회하기 - Emp기준
        EmpEntity empEntity = entityManager.find(EmpEntity.class, "bts7");
        System.out.println("bts7의 부서정보=>"+empEntity.getDept());
    }

    @Test
    public void test6() {
        //새로 삽입된 데이터를 조회하기 - Dept 기준
        DeptEntity deptEntity = entityManager.find(DeptEntity.class, 2L);
        System.out.println(deptEntity);

        //양방향은 양쪽의 모든 엔티티에서 각자방향으로 객체를 접근할 수 있다.
        List<EmpEntity> emplist = deptEntity.getEmplist();
        for (EmpEntity emp : emplist) {
            System.out.println(emp.getUserId());
        }
    }
    @Test
    public void test7() {
        //양방향으로 매핑되어있는 객체는
        //방향시 연관관계에서 주인이 아닌 역방향에 관계를 설정해서 코드를 넣지 않는다.
        // - mapped by 가 정의되어있는 엔티티는 조회만한다.
        //주체가 아닌 것을 이용해서 insert를 했기 때문에 dept가 셋팅되지 않는다.
        EmpEntity emp = new EmpEntity("bts5", " 뷔", "서울",
                new PrivateInfoEntity("bts5", "화랑", "서진이네"));
        entityManager.persist(emp);

        DeptEntity dept = new DeptEntity("TF팀","kbr");
        dept.getEmplist().add(emp);
        entityManager.persist(dept);
    }

    @Test
    public void test8() {
        DeptEntity dept = new DeptEntity("서비스팀","장동건");
        entityManager.persist(dept);

        EmpEntity emp = new EmpEntity("bts7", "슈가", "대구",
                new PrivateInfoEntity("bts7", "화양연화", "래퍼"),dept);
        entityManager.persist(emp);
    }

    @Test
    public void test9() {
        DeptEntity dept = entityManager.find(DeptEntity.class, "2");
        System.out.println(dept);
        List<HistoryEntity> historyEntityList = new ArrayList<>();

        historyEntityList.add(new HistoryEntity("D사", "front react개발"));
        historyEntityList.add(new HistoryEntity("E사", "Entity개발"));
        historyEntityList.add(new HistoryEntity("A사", "보안개발"));

        //주객체와 양방향매핑되는 객체에 변경된 내용을 반영시키기
        EmpEntity emp = EmpEntity.buildEmpEntity("lee2", "이민호", "서울",
                new PrivateInfoEntity("lee2", "신의", "푸른바다의전설"),
                historyEntityList, dept);
        entityManager.persist(emp);
    }
}

적용실습 in erp

디렉토리구조

CategoryController

//view를 랜더링하는 컨트롤러
@Controller
@RequestMapping("/category")
@RequiredArgsConstructor
public class CategoryController {
    private final CategoryService service;
    //page보기
    @GetMapping("write")
    public String categoryRegisterPage(){
        return "manage/product/category";
    }
    @PostMapping("write")
    public String categoryRegister(CategoryRequestDTO inputdto){
        System.out.println(inputdto);
        service.write(inputdto);
        return "manage/product/category";
    }
}

category.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/mainLayout}">
<head>
    <meta charset="UTF-8">
    <title>Insert title here</title>

</head>

<body>
<div class="container-fluid" layout:fragment="content">
    <h1>카테고리 등록</h1>
    <hr/>
    <form  class="form-horizontal"  action="/erp/category/write"   method="POST" name="myform">
        <fieldset>
            <div class="form-group">
                <!-- 카테고리명-->
                <div><a href="/erp/catgory/list">카테고리목록</a></div>
            </div>
            <div class="form-group">
                <!-- 카테고리명-->
                <label class="control-label col-sm-2" for="categoryName">카테고리명</label>
                <div class="col-sm-3">
                    <input type="text" id="categoryName" name="categoryName"
                           placeholder="카테고리명"
                           class="form-control"  >

                </div>
            </div>
            <div class="form-group">
                <!-- 비고-->
                <label class="control-label col-sm-2" for="info">비고</label>
                <div class="col-sm-3">
                    <input type="text" id="info" name="info"
                           placeholder="비고"
                           class="form-control"  >

                </div>
            </div>
            <div class="form-group">
                <!-- Button -->
                <div class="col-sm-3 col-sm-offset-2">
                    <input type="submit" value="등록하기" class="btn btn-success"/>
                </div>
            </div>
        </fieldset>
    </form>
</div>
</body>
</html>

CategoryDAOImpl

@Repository
@RequiredArgsConstructor
public class CategoryDAOImpl implements CategoryDAO{
    //스프링프레임워크가 CategoryRepository의 구현체를 만들어서 autowired한다.
    private final CategoryRepository repository;

    @Override
    public void write(CategoryEntity category) {
        //create
        repository.save(category);
    }

    @Override
    public List<CategoryEntity> findAll() {
        //List
        return repository.findAll();
    }

    @Override
    public List<CategoryEntity> pagingFindAll() {
        return List.of();
    }

    @Override
    public CategoryEntity findById(long categoryId) {
        //read
        return repository.findById(categoryId).get();
    }
}

CategoryServiceImpl

@Service
@RequiredArgsConstructor
public class CategoryServiceImpl implements CategoryService{
    private final CategoryDAO dao;
    @Override
    public void write(CategoryRequestDTO category) {
        //컨트롤러에서 넘겨받은 CategoryRequestDTO를 entity로 변환해서 넘기기
        //step01 - 생성자를 이용해서 직접 변경
        CategoryEntity entity = new CategoryEntity(category.getCategoryName(),
                                                 category.getInfo());
        dao.write(entity);
    }

    @Override
    public List<CategoryResponseDTO> findAll() {
        return List.of();
    }

    @Override
    public List<CategoryResponseDTO> pagingFindAll() {
        return List.of();
    }

    @Override
    public CategoryResponseDTO findById(long categoryId) {
        //Entity를 DTO로 변환해서 넘기기
        //step2 builder를 활용해서 작업하기
        CategoryEntity entity = dao.findById(categoryId);

        return CategoryResponseDTO.builder()
                .categoryId(entity.getCategoryId())
                .categoryName(entity.getCategoryName())
                .info(entity.getInfo())
                .build();
    }
}

CategoryResponseDTO

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class CategoryResponseDTO {
    private Long categoryId;
    private String categoryName;
    private String info;
}

CategoryRequestDTO

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class CategoryRequestDTO {
    private String categoryName;
    private String info;

}

CategoryEntity

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "category")
public class CategoryEntity {
    @Id
    @GeneratedValue
    private Long categoryId;
    private String categoryName;
    private String info;

    public CategoryEntity(String categoryName, String info) {
        this.categoryName = categoryName;
        this.info = info;
    }
}

CategoryAPIController

//api패키지의 모든 컨트롤러는 RestController
//JSON을 리턴하는 메소드
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
//로그기록
@Slf4j
public class CategoryAPIController {
    private final CategoryService categoryService;
    //카테고리를 추가하기 위한 데이터를 JSON으로 입력받고 싶은 경우
    //JSON으로 입력데이터를 만들어서 요청하면 스프링이 DTO로 변환
    //작업이 완료되면 성공완료됐는지만 넘기기
    //@RequestBody ---> json데이터 -> DTO로 변환해서 매개변수에 전달
    //@RequestBody ---> 자바객체 -> json데이터로 변환해서 응답
    @PostMapping("/category/insert")
    public ResponseEntity<?> insert(@RequestBody CategoryRequestDTO inputdata){
        System.out.println(inputdata);
        categoryService.write(inputdata);
        //ResponseEntity는 상태코드와 응답데이터의 본문을 설정
        //성공응답을 200 응답을 생성하고 별도의 본문없이 응답을 반환 - ok메시지
       // return ResponseEntity.ok().build(); ->원래 이렇게하면됨 밑은 ok사인 찍고싶어서하는것
        return ResponseEntity.ok(HttpStatus.OK);
    }
    @GetMapping("/category/{categoryId}")
    public CategoryResponseDTO read(@PathVariable("categoryId") String catrgoryId){
        return categoryService.findById(Long.parseLong(catrgoryId));
    }
}


본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.

0개의 댓글