[실험] 프록시와 CASCADE 를 더 잘 이해하기 위한 테스트

CASCADE 실험들


cascade: 연관된 객체끼리 연속적으로 persist 적용가능


team - member - locker 세 객체는 각각 1:N, 1:1 관계의 객체들이다

이 객체들은 모두 서로 연관관계 매핑이 되어있다

이때 CascadeType.PERSIST 로 설정하고

team 객체만을 저장하면 연관된 객체가 모두 저장된다

cascade: 부모가 아닌 자식으로 저장해도 persist 가능


parentA.addChildren(childA, childB);

em.persist(childB);

cascade: 여러 깊이에 걸쳐서 적용이 되는가?


예를들어 grand parent > parent > child 대로 persiste 가 적용되는지를 실험해보았다

결론: 가능하다 !

비즈니스 로직

GrandParent grandParentA = GrandParent.builder().name("grand parent A").build();

Parent parentA = Parent.builder().name("parent A").build();
Parent parentB = Parent.builder().name("parent B").build();

Child childA = Child.builder().name("child A").build();
Child childB = Child.builder().name("child B").build();
Child childC = Child.builder().name("child C").build();

grandParentA.addParents(parentA, parentB);

parentA.addChildren(childA, childB);
parentB.addChildren(childC);

em.persist(grandParentA);

조부모 클라쓰

@Entity(name = "GRAND_PARENT")
@Builder
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class GrandParent {

	@Id
	@GeneratedValue(generator = "uuid_gen")
	@GenericGenerator(name = "uuid_gen", strategy = "uuid")
	private String id;

	private String name;

	@Builder.Default
	@OneToMany(mappedBy = "grandParent", cascade = CascadeType.PERSIST)
	private List<Parent> parents = new ArrayList<>();

	public void addParents(Parent... parents) {
		this.parents.addAll(Arrays.asList(parents));
		Arrays.stream(parents).forEach(parent -> parent.mapGrandParent(this));
	}
}

부모 클라쓰

@Entity
@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Parent {

	@Id @GeneratedValue
	private Long id;

	private String name;

	@Builder.Default
	@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
	private List<Child> children = new ArrayList<>();

	@JoinColumn(name = "GRAND_PARENT_ID")
	@ManyToOne(fetch = FetchType.LAZY)
	private GrandParent grandParent;

	public void addChildren(Child... children) {
		this.children.addAll(Arrays.asList(children));
		Arrays.stream(children).forEach(child -> child.mapParent(this));
	}

	public void mapGrandParent(GrandParent grandParent){
		this.grandParent = grandParent;
	}
}
@Entity
@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Child {

	@Id @GeneratedValue
	private Long id;

	private String name;

	@JoinColumn(name = "PARENT_ID")
	@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
	private Parent parent;

	public void mapParent(Parent parent) {
		this.parent = parent;
		parent.getChildren().add(this);
	}
}

Self Join을 하는 연관관계 경우 연쇄적으로 적용가능?


공부하는 개발자 핑구님의 궁금중 중에

Self Join을 하는 로직이 있어서 재귀적으로 적용한지도 실험해보았다 (delete)

이 경우는 연쇄적으로 적용가능하다 !

Folder

@Entity
@SequenceGenerator(
	name = "FOLDER_SEQ_GEN" ,
	sequenceName = "FOLDER_SEQ" ,
	initialValue = 1
)
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Folder {

	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE , generator = "FOLDER_SEQ_GEN")
	private long id;

	private String name;

	@ManyToOne
	@JoinColumn(name = "PARENT_ID")
	private Folder parent;

	@BatchSize(size = 900)
	@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
	private List<Folder> children = new ArrayList<>();

	@Override
	public String toString() {
		return "Folder{" +
			"id=" + id +
			", name='" + name + '\'' +
			'}';
	}
}

여러 뎁스에 걸친 orphanRemoval 테스트


조부모 > 부모 > 자식 구조일때

조부모의 특정 부모를 삭제하면 그때의 자식도 제거되는지를 테스트해보았다

grandParentA.getParents().remove(0);

결론
부모, 자식에 걸쳐서 모두 제거 된다

Parent와 Child 가 일대다
Parent와 ChildSecond 일대다

일 경우

부모를 삭제하면 자식도 삭제된다 !

Parent parentA = Parent.builder().name("parent A").build();

Child childA = Child.builder().name("child A").build();
Child childB = Child.builder().name("child B").build();

ChildSecond childSecond = ChildSecond.builder().name("child 2-A").build();

parentA.addChildren(childA);
parentA.addChildren(childB);

parentA.addChildrenSecond(childSecond);

em.persist(parentA);
em.flush();

em.remove(parentA);

기타 알게된 것 UUID 채번전략


https://github.com/LeoHeo/spring-tips/blob/master/jpa-uuid.md

https://github.com/hibernate/hibernate-orm/blob/9b00aaf9a55f9879a512b34c13dd25425264494b/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java#L64

https://kapentaz.github.io/jpa/Hibernate%EC%97%90%EC%84%9C-Custom-ID-%EC%83%9D%EC%84%B1%ED%95%98%EA%B8%B0/#




© 2020.12. by 따라쟁이

Powered by philz