ProgramingTip

일대일 최대 수용 모드 : 전체 객체를 가져 오지 않고 getId ()

bestdevel 2020. 12. 4. 19:52
반응형

일대일 최대 수용 모드 : 전체 객체를 가져 오지 않고 getId ()


전체 개체를로드하지 않고 일대일 관계의 ID를 가져오고 싶습니다. 다음과 같이 지연 로딩을 사용하여 할 수 있습니다.

class Foo { 
    @OneToOne(fetch = FetchType.LAZY, optional = false)
    private Bar bar; 
}


Foo f = session.get(Foo.class, fooId);  // Hibernate fetches Foo 

f.getBar();  // Hibernate fetches full Bar object

f.getBar().getId();  // No further fetch, returns id

f.getBar ()가 다른 가져 오기 오기를 트리거 하지 않습니다 . 최대 모드에서 실제로 Bar 개체를 가져 오지 않고 .getId ()를 호출 할 수있는 프록시 개체를 제공하고 싶습니다.

내가 도대체 ​​뭘 잘못하고있는 겁니까?


사용 속성 액세스 전략

대신에

@OneToOne(fetch=FetchType.LAZY, optional=false)
private Bar bar;

사용하다

private Bar bar;

@OneToOne(fetch=FetchType.LAZY, optional=false)
public Bar getBar() {
    return this.bar;
}

이제 잘 작동합니다!

식별자 getter 메서드가 아닌 메서드 호출하면 프록시가 초기화 됩니다. 그러나 속성 액세스 전략을 사용할 때만 작동합니다. 명심 해.

참조 : Hibernate 5.2 사용자 가이드


Arthur Ronald FD Garcia의 게시물에 추가하기 만하면됩니다. @Access(AccessType.PROPERTY)(또는 더 이상 사용하지 않는 ) 속성 액세스를 강제 할 수 있습니다. http://256stuff.com/gray/docs/misc/hibernate_lazy_field_access_annotations.shtml을 참조하십시오.@AccessType("property")

또 다른 해결책은 다음과 가변합니다.

public static Integer getIdDirect(Entity entity) {
    if (entity instanceof HibernateProxy) {
        LazyInitializer lazyInitializer = ((HibernateProxy) entity).getHibernateLazyInitializer();
        if (lazyInitializer.isUninitialized()) {
            return (Integer) lazyInitializer.getIdentifier();
        }
    }
    return entity.getId();
}

분리 된 배터리 작동합니다.


불행히도 허용되는 대답은 잘못되었습니다. 또한 다른 답변은 가장 명확한 솔루션을 제공하지 않습니다.

에 대한 속성 액세스 수준을 사용 IDBAR클래스입니다.

@Entity
public class Bar {

    @Id
    @Access(AccessType.PROPERTY)
    private Long id;

    ...
}

그렇게 간단합니다 :)


@AccessType ( "속성") 추가

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@AccessType("property")
protected Long id;

Hibernate Book이있는 Java Persistence는 "13.1.3 Understanding Proxies"에서 참조합니다.

데이터베이스 식별자 속성에만 액세스하는 한 프록시를 초기화 할 필요가 없습니다. (직접 필드 액세스로 식별자 속성을 매핑하는 경우 이것은 사실이 아닙니다. Hibernate는 getId () 메서드가 존재하는지조차 알지 못합니다. 호출하면 프록시를 초기화해야합니다.)

그러나이 페이지의 @xmedeko 답변을 기반으로 직접 필드 액세스 전략을 사용할 때에도 프록시를 초기화하지 않도록 해킹을 개발했습니다 . getId()아래와 같이 방법을 변경하십시오 .

대신에:

    public long getId() { return id; }

사용하다:

    public final long getId() {
        if (this instanceof HibernateProxy) {
            return (long)((HibernateProxy)this).getHibernateLazyInitializer().getIdentifier();
        }
        else { return id; }
    }

여기서 아이디어는 getId()메서드를으로 표시하여 final프록시가 재정의 할 수 없도록하는 것입니다. 그러면 메서드를 호출하면 프록시 코드를 실행할 수 없으므로 프록시를 초기화 할 수 없습니다. 메서드 자체는 인스턴스가 프록시인지 확인하고이 경우 프록시에서 ID를 반환합니다. 인스턴스가 실제 개체 인 경우 ID를 반환합니다.


org.hibernate.Session에는 엔터티를 지연로드하지 않고 작업을 수행하는 함수가 있습니다.

public Serializable getIdentifier (Object object)는 HibernateException을 던집니다.

최대 절전 모드 3.3.2.GA에서 발견 :

public Serializable getIdentifier(Object object) throws HibernateException {
        errorIfClosed();
        checkTransactionSynchStatus();
        if ( object instanceof HibernateProxy ) {
            LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
            if ( li.getSession() != this ) {
                throw new TransientObjectException( "The proxy was not associated with this session" );
            }
            return li.getIdentifier();
        }
        else {
            EntityEntry entry = persistenceContext.getEntry(object);
            if ( entry == null ) {
                throw new TransientObjectException( "The instance was not associated with this session" );
            }
            return entry.getId();
        }
  }

이제 여기에 jackson hibernate 데이터 유형 라이브러리가 있습니다.

https://github.com/FasterXML/jackson-datatype-hibernate

그리고 다음과 같은 기능을 구성 할 수 있습니다.

 Hibernate4Module hibernate4Module = new Hibernate4Module();
 hibernate4Module.configure(Hibernate4Module.Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS, true);

여기에는 지연로드 된 관계의 ID가 포함됩니다.


HQL 쿼리를 사용할 수 있습니다. getBar () 메서드는 데이터 바인딩 된 메서드를 호출 할 때까지 가져 오지 않는 프록시를 실제로 반환합니다. 나는 당신의 문제가 정확히 무엇인지 확실하지 않습니다. 배경을 좀 더 알려주시겠습니까?


다음과 같이 getter 메소드를 변경하십시오.

public Bar getBar() {
    if (bar instanceof HibernateProxy) {
        HibernateProxy hibernateProxy = (HibernateProxy) this.bar;
        LazyInitializer lazyInitializer = hibernateProxy.getHibernateLazyInitializer();
        if (lazyInitializer.getSession() == null)
            bar = new Bar((long) lazyInitializer.getIdentifier());
    }

    return bar;
}

참고 URL : https://stackoverflow.com/questions/2593722/hibernate-one-to-one-getid-without-fetching-entire-object

반응형