[SPRING] Spring Data JPA 저장소 : 조건 적으로 자식 엔티티를 가져 오는 방법
SPRINGSpring Data JPA 저장소 : 조건 적으로 자식 엔티티를 가져 오는 방법
특정 실행 매개 변수가 제공되지 않는 한 관련 엔티티를 페치하지 않도록 어떻게 JPA 엔티티를 구성 할 수 있습니까?
Spring의 문서에 따르면, 4.3.9. Fetch 및 LoadGraphs를 구성하려면 @EntityGraph 주석을 사용하여 쿼리에 페치 정책을 지정해야하지만, 런타임시 해당 엔터티를로드할지 여부를 결정할 수는 없습니다.
자식 엔티티를 별도의 쿼리로 가져 오는 것은 괜찮지 만 그렇게하기 위해 리포지토리 나 엔티티를 구성하여 자식을 검색하지 않아야합니다. 불행히도, 나는 이것을하는 방법에 대한 어떤 전략도 찾을 수없는 것 같습니다. FetchPolicy는 무시되며 EntityGraph는 열심히 검색 할 엔터티를 지정할 때만 유용합니다.
예를 들어 계정이 상위이고 연락처가 하위이고 계정에 많은 연락처가있을 수 있다고 가정합니다.
나는 이것을 할 수 있기를 바란다.
if(fetchPolicy.contains("contacts")){
account.setContacts(contactRepository.findByAccountId(account.getAccountId());
}
문제는 스프링 데이터가 어쨌든 연락처를 열심히 가져 오는 것입니다.
Account Entity 클래스는 다음과 같습니다.
@Entity
@Table(name = "accounts")
public class Account
{
protected String accountId;
protected Collection<Contact> contacts;
@OneToMany
//@OneToMany(fetch=FetchType.LAZY) --> doesn't work, Spring Repositories ignore this
@JoinColumn(name="account_id", referencedColumnName="account_id")
public Collection<Contact> getContacts()
{
return contacts;
}
//getters & setters
}
AccountRepository 클래스는 다음과 같습니다.
public interface AccountRepository extends JpaRepository<Account, String>
{
//@EntityGraph ... <-- has type= LOAD or FETCH, but neither can help me prevent retrieval
Account findOne(String id);
}
해결법
-
==============================
1.getContacts ()가 호출되어 객체의 메서드가 없으면 lazy fetch가 제대로 작동해야합니다.
getContacts ()가 호출되어 객체의 메서드가 없으면 lazy fetch가 제대로 작동해야합니다.
더 많은 수동 작업을 선호하고 실제로이 작업을 제어하고 싶다면 (유스 케이스에 따라 더 많은 컨텍스트가 필요할 수 있습니다.) 계정 엔터티에서 연락처를 제거하고 대신 연락처에 계정을 매핑하는 것이 좋습니다. hibernate에게 그 필드를 무시하도록 지시하는 한가지 방법은 @Transient 어노테이션을 사용하여 그것을 매핑하는 것이다.
@Entity @Table(name = "accounts") public class Account { protected String accountId; protected Collection<Contact> contacts; @Transient public Collection<Contact> getContacts() { return contacts; } //getters & setters }
그런 다음 서비스 클래스에서 다음과 같은 작업을 수행 할 수 있습니다.
public Account getAccountById(int accountId, Set<String> fetchPolicy) { Account account = accountRepository.findOne(accountId); if(fetchPolicy.contains("contacts")){ account.setContacts(contactRepository.findByAccountId(account.getAccountId()); } return account; }
희망이 당신이 찾고있는 것입니다. Btw, 코드는 테스트되지 않았으므로 다시 확인해야합니다.
-
==============================
2.이 경우 @Transactional을 사용할 수 있습니다.
이 경우 @Transactional을 사용할 수 있습니다.
이를 위해서는 계좌 엔티티를 느슨하게 가져와야합니다.
@ 트랜잭션 주석은 분리 할 수없는 모든 작업 주위에 배치해야합니다.
연락처를 열렬히 가져 오기 위해 하나의 플래그를 허용하는 메소드를 서비스 계층에 작성하십시오.
@Transactional public Account getAccount(String id, boolean fetchEagerly){ Account account = accountRepository.findOne(id); //If you want to fetch contact then send fetchEagerly as true if(fetchEagerly){ //Here fetching contacts eagerly Object object = account.getContacts().size(); } }
희망이 유용합니다. :)
자세한 내용은이 링크를 참조하십시오.
-
==============================
3.JPA 2.1에서 실행되는 예제를 찾으십시오.
JPA 2.1에서 실행되는 예제를 찾으십시오.
로드하려는 속성 만 attributeNodes 목록과 함께 설정하십시오.
엔티티 그래프 주석이있는 엔티티 :
@Entity @NamedEntityGraph(name = "accountGraph", attributeNodes = { @NamedAttributeNode("accountId")}) @Table(name = "accounts") public class Account { protected String accountId; protected Collection<Contact> contacts; @OneToMany(fetch=FetchType.LAZY) @JoinColumn(name="account_id", referencedColumnName="account_id") public Collection<Contact> getContacts() { return contacts; } }
사용자 정의 인터페이스 :
public interface AccountRepository extends JpaRepository<Account, String> { @EntityGraph("accountGraph") Account findOne(String id); }
"accountId"속성 만 열심히로드됩니다. 다른 모든 속성은 액세스 할 때 느리게로드됩니다.
-
==============================
4.스프링 데이터는 fetch = FetchType.Lazy를 무시하지 않습니다.
스프링 데이터는 fetch = FetchType.Lazy를 무시하지 않습니다.
내 문제는 도저 매핑을 사용하여 내 엔티티를 그래프로 변환하는 것이 었습니다. 분명히 도저는 getters와 setter를 두 개의 객체를 매핑하도록 호출하므로 PersistentCollections를 무시하기 위해 사용자 정의 필드 매퍼 구성을 추가해야했습니다.
GlobalCustomFieldMapper.java:
public class GlobalCustomFieldMapper implements CustomFieldMapper { public boolean mapField(Object source, Object destination, Object sourceFieldValue, ClassMap classMap, FieldMap fieldMapping) { if (!(sourceFieldValue instanceof PersistentCollection)) { // Allow dozer to map as normal return; } if (((PersistentCollectiosourceFieldValue).wasInitialized()) { // Allow dozer to map as normal return false; } // Set destination to null, and tell dozer that the field is mapped destination = null; return true; } }
from https://stackoverflow.com/questions/33266952/spring-data-jparepository-how-to-conditionally-fetch-children-entites by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] RestTemplate PATCH 요청 (0) | 2019.02.06 |
---|---|
[SPRING] @Autowire (required = false)와 같이 @Inject를 JSR 330에서 선택적으로 사용할 수 있습니까? (0) | 2019.02.06 |
[SPRING] Spring JDBC에서 현재 Connection 객체를 얻는 방법 (0) | 2019.02.06 |
[SPRING] 봄에 필수 속성을 정의하는 방법은 무엇입니까? (0) | 2019.02.06 |
[SPRING] java.lang.IllegalStateException : ApplicationEventMulticaster가 초기화되지 않음 [닫힘] (0) | 2019.02.06 |