해결된 질문
작성
·
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
오 빠르고 정확한 답변 감사드립니다!
강의는 없었지만 강사님이 쓰신 책에 보니 상세히 적혀있네요ㅎㅎ
참고하겠습니다!
update문 없애겠다고 하루종일 고민했었는데 정말 감사합니다ㅠㅠ
1
안녕하세요. Chung A님^^!
일대다 단방향 매핑을 사용하셨군요!!! 에헴
이렇게 추가로 update가 발생한 것은 복사 때문이 아니라 일대다 단방향 매핑의 특징이면서 단점입니다^^!
일대다 단방향 매핑 대신에 다대일, 일대다 양방향 매핑으로 바꾸어 사용하면 추가 update 쿼리 문제가 해결됩니다.
연관관계 매핑은 설계와 관련된 부분이기 때문에 JPA를 잘 사용하려면 확실히 알아야 하고, 각각의 장단점을 이해해야 합니다.
JPA 기본편 -> 다양한 연관관계 매핑 -> 일대다에서 왜 이런 문제가 발생하는지, 그리고 대안은 어떤 것들이 있는지 매우 자세하게 설명드립니다.
혹시 JPA 기본편을 듣지 않으셨다면, 지금 시점에 한번 JPA 기본편을 듣는 것을 추천드립니다^^!
감사합니다.