======================================================================================================================================================================
결론 : 1.조인해서 한번의 Query 로 Load 하려면 @EntityGraph 를 사용하여야 한다.
2. @NamedEntityGraph 선언할때 @NamedAttributeNode 에 원쿼리로 가져올 항목을 명시한다.
3. Repository 메소드에 @EntityGraph 선언하여 value에 사용할 @NamedEntityGraph 명을 적고, type 은 = EntityGraph.EntityGraphType. LOAD , FETCH 선택 사용.
4. 조인해서 가져오는 항목외에 다른 객체필드에 LAZY ,EAGER 를 선언해서 적어준다.
자세한 내용은 아래 참조.
======================================================================================================================================================================
엔티티 필드에 사용하는 LAZY, EAGER 를 Repository(메소드) 마다 다르게 사용하기 위해서 @NamedEntityGraph , @EntityGraph 를 사용한다.
@NameEntityGraph [ name = 이름을 선언 , attributeNodes = 조인해서 가져올 항목들 선언 ]
@EntityGraph [ value = NameEntityGraph name 값 , type = FETCH,LOAD 선택 ]
- FETCH: entity graph에 명시한 attribute는 EAGER로 패치하고, 나머지 attribute는 LAZY로 패치
- LOAD: entity graph에 명시한 attribute는 EAGER로 패치하고, 나머지 attribute는 entity에 명시한 fetch type이나 디폴트 FetchType으로 패치 (e.g. @OneToMany는 LAZY, @ManyToOne은 EAGER 등이 디폴트이다.)
* 이슈가 생겨서 쿼리수정이 필요할때
FETCH 로 선언했었을때 : EAGER 로 변경하고 싶을때 attribute 에 추가, LAZY 로 변경하고싶을경우 attribute에서 제거.
LOAD 로 선언했었을때 : EAGER 로 변경하고 싶을때 attribute 에 추가, LAZY 로 변경하고싶을경우 Entity 속성을 수정.
(여기서 Entity를 수정하는건 다른 API에 영향이 가기 때문에, FETCH 로 선언을 해서 사용하는게 추후 쿼리 이슈가 발생 했을경우 수정이 자유롭지 않을까 싶다.)
참고 : attributePaths 는 value 를 사용안하고 바로 필드를 적을때 사용.(value를 사용하는게 명시적으로 좋을듯하다) , subgraphs ( 2개이상 엔티티 조인할때 필요 )
Organization.java
@NamedEntityGraph(name = "Organization.subOrgList", attributeNodes = {@NamedAttributeNode("subOrganizationList")},subgraphs = {@NamedSubgraph(name = "subOrg",attributeNodes = @NamedAttributeNode("subOrganizationList"))})
public class Organization extends AbstractEntity implements AggregateRoot {
...................
...................
}
|
OrganizationRepository.java
@RepositoryRestResource
public interface OrganizationRepository extends
JpaRepository<Organization, Long>, QuerydslPredicateExecutor<Organization>
, QuerydslBinderCustomizer<QOrganization> {
@EntityGraph(value = "Organization.subOrgList",attributePaths = {"parent"},type = EntityGraph.EntityGraphType.LOAD)
Optional<Organization> findFirstByOrganizationCode(String organizationCode);
@EntityGraph(value = "Organization.subOrgList",attributePaths = {"parent"},type = EntityGraph.EntityGraphType.LOAD)
Page<Organization> findAll(Pageable pageable);
List<Organization> findAllBy();
....
}
|
========================================================================================================================================================
LAZY , EAGER 차이
fetch= FetchType.LAZY:데이터를 가져다 쓰는 시점에 쿼리를 실행한다. ( 즉 projection 으로 사용하지 않는 필드를 조회하는 API 를 호출할땐 쿼리가 실행되지 않음 )
fetch= FetchType.EAGER:데이터를 가져옴 조인해서 가져온다.( 단 Page<Entity> findAll(Pageable pageable) 메소드에는 적용되지 않음. @EntityGraph 사용해줘야됨 )
public class Organization extends AbstractEntity implements AggregateRoot {
.....................
.....................
@OneToMany(mappedBy="parent", fetch= FetchType.LAZY, cascade=CascadeType.ALL)
@RestResource(exported=false)
@JsonManagedReference
public List<Organization> subOrganizationList;
}
|
ex) projection 으로 subOrganizationList