2009-06-08 3 views
1

은 다음과 실체 B.게으른 부하에 HQL을 통해 일대일 구성은

매핑을 가진 양방향 one-또는 제로 -에 - 하나의 매핑 엔티티 A를하는 경우되는 방법과 같이

<class name="EntityA" table="TABLE_A" mutable="true" lazy="true"> 
    <id name="idA" type="long" column="pk_a" unsaved-value="null"> 
     <generator class="sequence"> 
      <param name="sequence">pk_a_seq</param> 
     </generator> 
    </id> 
    <one-to-one name="propertyB" class="EntityB" property-ref="propertyA" constrained="true" outer-join="false"/> 
</class> 

<class name="EntityB" table="TABLE_B" mutable="true" lazy="true"> 
    <id name="idB" type="long" column="pk_b" unsaved-value="null"> 
     <generator class="sequence"> 
      <param name="sequence">pk_b_seq</param> 
     </generator> 
    </id> 
    <many-to-one name="propertyA" class="EntityA" not-null="true" unique="true" lazy="proxy" column="fk_a"/> 
</class> 

내가 EntityA에 대한 (또는 오히려, 명명 된 HQL 질의)는 HQL 질의를 할

, 열심히 최대 절전 모드는 별도의 선택 문 EntityA # propertyB를로드합니다.

나의 hql이 1000 EntityA (자신의 각각의 EntityB를 가지고 있음)를 반환하고, 최대 절전 모드가 n + 1 쿼리를 수행하면 문제가 생길 수 있습니다 (n 쿼리가 오는 동안 EntityA가 1000 개의 결과를 반환합니다) EntityA # 속성 B에서 지연로드 선택).

그러나 EntityA # propertyB가 필요하지 않으므로 별도의 SQL 쿼리를 사용하지 않고 최대 절전 모드로 설정하지 않고 게으르며로드하려고합니다.

그럴 수 있습니까? 그리고 만약 그렇다면 어떻게해야합니까?

감사합니다, 프란츠

+0

정확하게 문제를 이해하지 못합니다. 당신이 EntityA의 집합에 대해 hql을 수행한다면, 프록시 메소드 EntityA.getPropertyB()를 호출 할 때마다 상응하는 EntityA # propertyB가 별도의 쿼리를 통해로드 될 것입니다. 이것은 정상적인 지연로드 동작입니다. 그 행동을 정확히하고 싶습니까? –

+0

문제는 query.list()로 n + 1을 얻었 기 때문입니다. 내 조사에서 두 가지 원인이 있습니다 :). session.getNamedQuery ("myQueryString"). .list()를 실행하면 Hibernate는 일치하는 모든 EntityA를 EntityA # getPropertyB 열심히 초기화했다. b.) EntityA # getPropertyB()는 별도의 select 문을 통해 초기화됩니다. 따라서 하나의 query.list()를 사용하면 이미 n + 1 문제가 발생합니다. 내가 (a.) 또는 (b.) 중 하나를 제거 할 수 있다면, 내 n + 1을 풀 수있을 것입니다. preferrably, 나는 (a.)을 제거 할 수 있었다. –

답변

2

이 문제가 해결되었습니다.

내가 한 것은 필드 EntityA # propertyB를 이름이 EntityA # propertyBs 인 집합으로 바꾸는 것입니다. 하지만 EntityA # getPropertyB() 및 EntityA # setPropertyB (EntityB 속성 B) 접근 자 메서드를 유지했습니다.

public EntityB getPropertyB() { 
    return CollectionUtils.get(propertyBs, 0); 
} 

public void setPropertyBs(EntityB propertyB) { 
    propertyBs= Collections.singleton(propertyB); 
} 

그런 다음 내 매핑에서, 내가 설정 EntityA # propertyBs를 매핑 '필드'에 대한 액세스를 지정하는 접근 방법의

방법의 몸은 이제이 같은입니다.

이 설정으로
<set name="scheduledAdInfos" lazy="true" fetch="subselect" access="field" cascade="none" inverse="true"> 
    <key column="pk_a"/> 
    <one-to-many class="EntityB"/> 
</set> 

, 당신은 지금 TABLE_A이 TABLE_B가 소유해도 소유 POJO (EntityB)에 대한 소유 POJO (EntityA)에서 게으른 매핑을 만들 수 있습니다.

0

짧은 답변 : 아니 당신이 적어도 데이터베이스 및 매핑을 변경하지 않고, 그렇게 할 수 없습니다. 기본적으로 일대일 매핑과 외래 키 관계를 원하는 방식으로 바꿔야합니다.


긴 대답 : 최대 절전 모드 수 게으른 부하 협회. 이를 수행하는 방법은 참조 된 객체의 ID를 보유하는 프록시 객체를 삽입하는 것입니다.

경우에 따라 매핑은 외래 키 열이 TABLE_B, 즉 다 대일 매핑을 사용하는 것과 같습니다. 따라서 B를로드하면, hibernate는 fk_a 컬럼에서 FK 참조를 찾고이 값을 보유하는 프록시를 생성 할 수있다. 프록시가 액세스되면 해당 엔티티가로드됩니다.

테이블 A의 레코드를 선택하면 어떻게됩니까? Hibenate는 A 객체를 만들지 만 속성 B를 채울 수 있으려면 TABLE_B를 조사하여 fk_a = a.id로 해당 행을 찾아야합니다. Hibernate가 게으른 로딩 시간에로드 할 레코드를 찾기위한 다른 방법은 없다.

실제로 이것은 다른 고유 키를로드하는 동안 지연로드를 수행 할 수 있어야하므로 Hibernate에 대한 개선점이 될 수 있지만 현재 구현에서는 허용하지 않으므로 문제가 발생할 수 있습니다.

관련 문제