2011-03-10 5 views
23

Hibernate Envers에서, 어떤 fetch 타입이 설정되었는지에 관계없이 엔티티의 모든 관련된 콜렉션들이 지연되어로드된다. 따라서 다른 엔티티 (물론 두 감사 대상 모두)의 콜렉션을 가진 엔티티에 대한 auditquerying을 수행하면 컬렉션은 처음에는 SetProxy입니다 (디버깅 할 때 볼 수 있음).Hibernate Envers : Initiating Proxys

어떻게 프록시를 초기화 할 수 있습니까? Hibernate.initialize()을 사용하는 것은 효과가 없다. (나는 Hibernate와 Envers가 다른 프록시 객체를 사용하기 때문에 의심된다.) 나는 항목을 반복하여 세트를 초기화 할 수 있다는 것을 알고 있지만 엔티티에 여러 콜렉션이 있고 유지 보수 문제는 언급하지 않기 때문에이 옵션이 나를위한 옵션이 아닙니다.

최대 절전 모드 세션이 이미 닫혀있을 때 (도메인 개체를 dtos로 변환) 나중에 컬렉션에 액세스하기 때문에 열심히 초기화해야합니다.

나는 최대 절전 모드 3.5.6을 사용하고있다.

+0

나는이 일을 할 수 없다! Envers는 가져 오기 계획을 무시하는 것 같습니다! SELECT Fetch 모드로 열심히 가져 오기 위해 설정 한 엔티티가 여러 개 있습니다 (항상 2 차 캐시에 있음 - 읽기 전용 및 영원).JSP를 렌더링 할 때 게으른 초기화 오류가 발생합니다. 고통은 당신이 알고 있습니다. :(Grrr! – les2

답변

13

분명히, 이것은 Hibernate Envers의 열린 문제입니다. 이미 JIRA에 기존 문제가 있습니다 : https://hibernate.atlassian.net/browse/HHH-3552. 이 투표에 자유롭게, 어쩌면 속도를 높여서이 문제를 해결하려는 사람들이 있음을 알게 될 것입니다.)

Envers 팀에서이 문제를 해결할 때까지 저에게 적합한 해결 방법이 있습니다 : 모음에서 size()을 호출하면 프록시 개체가 초기화됩니다.

+1

Hibernate.initialize()가 우리에게 적합하지 않습니다. –

-2

디자인에 문제가 있습니다.

인터셉터 내부에서 초기화해야하는 경우 (최대 절전 모드 호출을 가로 채어 작동하는 것으로 생각됩니다) 도메인 모델에 대해 을 미리 알고 있어야합니다. 감사는 도메인 모델링에서 완전히 독립적 인 관심사 여야합니다.

이 당신이 컬렉션을 반복하는 몇 가지 일반적인 반사 방법을 사용하여 자신의 이니셜을 롤백 할 수 있습니다, 또는 당신은 오픈 세션에서-보기 패턴을 사용할 수 있으며, 즉, 내부 (Envers 작업에 적응 말했다 데 귀하의 인터셉터).

이러한 항목에 액세스하면 다른 쿼리가 트리거되므로 로그를 분석 할 때 혼동을 줄 수 있음에 유의하십시오.


편집 : 그 최대 절전 모드 당신이 선택 런타임에 계획을 인출 할 수있는 프로파일을 가져 오는 것 같다. 이 부분은 SO questiondocs입니다.

+0

"인터셉터 내부에서 초기화하는 것"이 ​​무슨 뜻인지 잘 모르겠다. 결국 Envers API (AuditReader를 통해 AutitQuery를 실행)에 의해 도메인 객체를 얻고있다.하지만, 내 문제는 나중에 알게 되듯이 열려있는 문제 (http://opensource.atlassian.com/projects/hibernate/browse/HHH-3552)입니다. –

+0

같은 문제가 있습니다. 어떻게 그 문제를 해결 했습니까? – ndtreviv

+0

콜렉션에서'size()'를 호출하면 Envers 프록시 객체가 초기화됩니다 .. –

4

Envers 프록시를 초기화하기 위해 지금까지 발견 한 최선의 방법은 Dozer입니다. Envers가 반환 한 감사 대상 엔터티를 자체에 매핑하면 초기화가 강제됩니다. 예를 들어

:

// Assuming you have an initialized EntityManager in entityManager & 
    // id contains your entity id.. 

    List<Object[]> auditList = (List<Object[]>)AuditReaderFactory. 
            get(entityManager). 
            createQuery(). 
            forRevisionsOfEntity(Foo.class, false, true). 
            add(AuditEntity.id().eq(id)). 
            getResultList(); 

    // Use a singleton in production apps instead... 
    DozerBeanMapper mapper = new DozerBeanMapper(); 

    for(Object[] audit : auditList) { 
     audit[0] = mapper.map(audit[0], Foo.class); 
    } 

    // The proxies in the Foo instances in auditList are now initialized 

나는이 솔루션에 매우 만족 모르겠지만, 수동으로 컬렉션을 터치하여 프록시를 초기화 이상을 선호합니다. 누군가가 더 나은 대안을 제시하거나 HHH-3552가 고쳐지기를 바랍니다!

+0

좋은 해결책이지만 전체 객체 그래프의 모든 클래스에있는 모든 속성에 대해 올바른 getter 및 setter 이름을 지키지 않아서 발생하는 버그에주의하십시오. 예를 들어 부울 속성에 대한 오류가있을 수 있습니다 (예 : http://stackoverflow.com)./questions/532264 8/for-a-boolean-field-what-is-the-getter-setter – user598656

관련 문제