Hibernate one-to-one: getId () без извлечения всего объекта
Я хочу получить идентификатор отношения один-к-одному без загрузки всего объекта. Я думал, что смогу сделать это с помощью ленивой загрузки следующим образом:
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 () to не вызвать другую выборку. Я хочу, чтобы hibernate дал мне прокси-объект, который позволяет мне звонить .getId () без фактического извлечения объекта Bar.
что я делаю не так?
9 ответов:
использовать стратегия доступа к собственности
вместо
@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 руководство пользователя
просто чтобы добавить к Arthur Ronald 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(); }
работает и для отдельных объектов.
добавить @AccessType ("свойство")
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @AccessType("property") protected Long id;
Java Persistence with Hibernate Book упоминает об этом в "13.1.3 понимание Прокси":
пока вы обращаетесь только к свойству идентификатора базы данных, нет инициализация прокси-сервера необходима. (Обратите внимание, что это не так если вы сопоставляете свойство identifier с прямым доступом к полю; 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
наBAR
класса.@Entity public class Bar { @Id @Access(AccessType.PROPERTY) private Long id; ... }
просто :)
в org.зимовать.Сеанс у вас есть функция, которая выполняет работу без ленивой загрузки сущности:
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);
это будет включать идентификатор ленивого загруженного отношения -
вы можете использовать запрос HQL. Метод getBar () действительно вернет прокси-сервер, который не будет извлечен, пока вы не вызовете какой-либо метод привязки данных. Я не уверен, в чем именно заключается ваша проблема. Можете ли вы дать нам еще немного фона?
измените метод геттера следующим образом:
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; }