Hibernate один-к-одному: getId () без извлечения всего объекта - PullRequest
58 голосов
/ 07 апреля 2010

Я хочу получить идентификатор отношения один-к-одному без загрузки всего объекта. Я думал, что смогу сделать это с помощью отложенной загрузки следующим образом:

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 (), чтобы не инициировал другую выборку. Я хочу, чтобы hibernate дал мне прокси-объект, который позволяет мне вызывать .getId () без фактического извлечения объекта Bar.

Что я делаю не так?

Ответы [ 9 ]

39 голосов
/ 08 апреля 2010

Использование стратегии доступа к свойству

Вместо

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

Использование

private Bar bar;

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

Теперь все работает отлично!

Прокси инициализируется, если вы вызываете любой метод , который не является методом получения идентификатора .Но это работает только при использовании стратегии доступа к свойству.Имейте это в виду.

См .: Руководство пользователя Hibernate 5.2

27 голосов
/ 13 июля 2010

Просто добавьте в Артур Рональд F D Garcia'post: вы можете принудительно получить доступ к собственности на @Access(AccessType.PROPERTY) (или устарела @AccessType("property")), см. http://256stuff.com/gray/docs/misc/hibernate_lazy_field_access_annotations.shtml

Другое решение может быть:

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();
}

Работает и для отдельных объектов.

14 голосов
/ 10 октября 2016

К сожалению, принятый ответ неверен. Также другие ответы не обеспечивают самое простое или ясное решение.

Используйте уровень доступа к свойству для ID класса BAR.

@Entity
public class Bar {

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

    ...
}

Так же просто, как это:)

14 голосов
/ 14 сентября 2015

добавить @ AccessType ("свойство")

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@AccessType("property")
protected Long id;
7 голосов
/ 15 июля 2015

Java Persistence с Hibernate Book упоминает об этом в «13.1.3 Понимание прокси»:

Пока вы обращаетесь только к свойству идентификатора базы данных, нет инициализация прокси необходима. (Обратите внимание, что это не так если вы сопоставите свойство идентификатора с прямым доступом к полю; зимовать тогда даже не знает, что метод 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, чтобы прокси не могли его переопределить. Затем вызов метода не может запустить какой-либо прокси-код и, следовательно, не может инициализировать прокси. Сам метод проверяет, является ли его экземпляр прокси, и в этом случае возвращает идентификатор прокси. Если экземпляр является реальным объектом, он возвращает идентификатор.

3 голосов
/ 20 августа 2012

В org.hibernate.Session у вас есть функция, которая выполняет работу без ленивой загрузки сущности:

public Сериализуемый getIdentifier (Объектный объект) выдает 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();
        }
  }
2 голосов
/ 26 июля 2016

Здесь есть библиотека типов данных гибернации Джексона:

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

И вы можете настроить функции:

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

Это будет включать в себя идентификатор ленивых загруженных отношений-

0 голосов
/ 12 сентября 2015

измените свой метод получения, как это:

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;
}
0 голосов
/ 07 апреля 2010

Вы можете использовать HQL-запрос.Метод getBar () действительно вернет прокси, который не будет извлечен, пока вы не вызовете какой-либо метод с привязкой к данным.Я не уверен, что именно ваша проблема.Можете ли вы дать нам немного фона?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...