인프런 커뮤니티 질문&답변

Chung A님의 프로필 이미지
Chung A

작성한 질문수

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

oneToMany 관계의 엔티티 값들을 일부 변경하여 새롭게 insert하는 방법에 대하여 질문드립니다!

해결된 질문

작성

·

547

0

안녕하세요 강사님!

항상 빠르고 명쾌한 답변 감사드립니다:D

 

강의에서 알려주신 일대 다 관계의 엔티티는 ToOne관계의 데이터들을 조회한 뒤

ToMany관계의 컬렉션들을 따로 조회해서 붙여주는 내용에 대한 실습을 하던 중이였는데요,

여기서 추가로 기존에 DB에 있는 엔티티를 ID값만 바꿔서 새로운 엔티티로 insert하고자 하다가 

생각한대로 동작이 잘 안되서 질문드립니다.

 

여기서 이 엔티티를 insert하고 끝날줄 알았는데 insert가 끝나고 복수의 update문이 실행됩니다ㅠ

이 현상에 대해 아무리 생각해도 모르겠어서 질문드립니다!

 

아래는 테스트했던 소스코드입니다!

혹시 몰라서 같이 첨부드립니다

 

[부모 엔티티-TestEntity]

@Entity
@Data
public class TestEntity {

@Id
private String parentId;
private String parentName;
@OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
@JoinColumn(name = "parentId")
private List<ChildEntity> childList;
}

[자식 엔티티-childEntity]

@Entity
@Data
public class ChildEntity {

@Id
private String childId;
private String parentId;
private String childName;
}

 

[Controller]

@RestController
public class TestController {

@Autowired
TestRepository testRepository;


@GetMapping("/entityTest")
public String entityTest(){
List<TestEntity> list=
testRepository.selectParentByName("parent");

List<String> idList = list.stream().map(TestEntity::getParentId).collect(Collectors.toList());
Map<String, List<ChildEntity>> collect = testRepository.selectChildList(idList)
.stream().collect(Collectors.
groupingBy(ChildEntity::getParentId));

List<TestEntity> result = list.stream().map(
p -> copyParentEntity(p
,collect.get(p.getParentId()))
).collect(Collectors.
toList());

testRepository.saveAll(result);
return "test";
}

public TestEntity copyParentEntity(TestEntity t,List<ChildEntity> childList){
TestEntity newTest=
new TestEntity();
newTest.setParentId("C"+ System.currentTimeMillis()+"_"+t.getParentId());
newTest.setParentName(t.getParentName());
newTest.setChildList(copyChildList(childList,newTest.getParentId()));
return newTest;
}

private List<ChildEntity> copyChildList(List<ChildEntity> childList, String parentId){
ArrayList<ChildEntity> result =
new ArrayList<>();

for (int i=0;i<childList.size();i++) {
ChildEntity c=
new ChildEntity();
c.setChildId(parentId+i);
c.setParentId(parentId);
c.setChildName(childList.get(i).getChildName());
result.add(c);
}
return result;
}
}

 

[리포지토리-TestRepository]

public interface TestRepository extends JpaRepository<TestEntity,String> {

@Query("select t from TestEntity t " +
"where t.parentName=:parentName")
List<TestEntity> selectParentByName(@Param("parentName")String parentName);


@Query("select c from ChildEntity c " +
"where c.parentId in :parentIds")
List<ChildEntity> selectChildList(@Param("parentIds")List<String> ids);
}

[DB데이터-parentEntity]

[DB데이터-childEntity]

▶실행결과 로그

 

1) insert문

insert into test_entity (parent_name, parent_id) values ('parent', 'C1600949255895_1');

insert into child_entity (child_name, parent_id, child_id) values ('child1', 'C1600949255895_1', 'C1600949255895_10');

insert into child_entity (child_name, parent_id, child_id) values ('child2', 'C1600949255895_1', 'C1600949255895_11');

insert into test_entity (parent_name, parent_id) values ('parent', 'C1600949255895_2');

insert into child_entity (child_name, parent_id, child_id) values ('child3', 'C1600949255895_2', 'C1600949255895_20');

insert into child_entity (child_name, parent_id, child_id) values ('chlid4', 'C1600949255895_2', 'C1600949255895_21');

 

2) update문

update child_entity set parent_id='C1600949255895_1' where child_id='C1600949255895_10';

update child_entity set parent_id='C1600949255895_1' where child_id='C1600949255895_11';

update child_entity set parent_id='C1600949255895_2' where child_id='C1600949255895_20';

update child_entity set parent_id='C1600949255895_2' where child_id='C1600949255895_21';

 

보시다시피 이미 insert에서 parent_id값들이 다 제대로 들어가고 있는데

같은 값을 set해주는 update문이 실행되고 있어서 왜그런지 모르겠네요...

 

아니면 혹시 제가 한 방법 외에 엔티티를 복사해주는 좋은 방법이 있다면 알려주시면 감사드리겠습니다ㅠㅠ

바쁘실텐데 긴 글 읽어주셔서 감사합니다! 

답변 2

1

Chung A님의 프로필 이미지
Chung A
질문자

오 빠르고 정확한 답변 감사드립니다!

강의는 없었지만 강사님이 쓰신 책에 보니 상세히 적혀있네요ㅎㅎ

참고하겠습니다!

update문 없애겠다고 하루종일 고민했었는데 정말 감사합니다ㅠㅠ 

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. Chung A님^^!

일대다 단방향 매핑을 사용하셨군요!!! 에헴

이렇게 추가로 update가 발생한 것은 복사 때문이 아니라 일대다 단방향 매핑의 특징이면서 단점입니다^^!

일대다 단방향 매핑 대신에 다대일, 일대다 양방향 매핑으로 바꾸어 사용하면 추가 update 쿼리 문제가 해결됩니다.

연관관계 매핑은 설계와 관련된 부분이기 때문에 JPA를 잘 사용하려면 확실히 알아야 하고, 각각의 장단점을 이해해야 합니다.

JPA 기본편 -> 다양한 연관관계 매핑 -> 일대다에서 왜 이런 문제가 발생하는지, 그리고 대안은 어떤 것들이 있는지 매우 자세하게 설명드립니다.

혹시 JPA 기본편을 듣지 않으셨다면, 지금 시점에 한번 JPA 기본편을 듣는 것을 추천드립니다^^!

감사합니다.

Chung A님의 프로필 이미지
Chung A

작성한 질문수

질문하기