hibernate一对一: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() 不会触发另一个提取。 我想hibernate给我一个代理对象,允许我调用.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'post:您可以通过@Access(AccessType.PROPERTY) (或已弃用的@AccessType("property") )强制访问@AccessType("property") ,请参阅http://256stuff.com/gray/docs/杂项/ hibernate_lazy_field_access_annotations.shtml

另一个解决scheme可能是

 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了解代理”中提到了这一点:

只要您只访问数据库标识符属性,就不需要初始化代理服务器。 (请注意,如果将标识符属性与直接字段访问进行映射,则不是这样,Hibernate甚至不知道getId()方法存在,如果调用它,则必须初始化代理。

但是,基于@xmedeko在这个页面中的回答,我开发了一个hack, 即使在使用直接字段访问策略时也避免初始化代理。 只需改变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。

不幸的是接受的答案是错误的。 另外其他答案不提供最简单或明确的解决scheme。

使用属性访问级别作为BAR类的ID

 @Entity public class Bar { @Id @Access(AccessType.PROPERTY) private Long Id; ... } 

就像那么简单:)

在org.hibernate.Session中,你有一个没有延迟加载实体的function:

public Serializable getIdentifier(Object object)抛出HibernateException;

发现在hibernate3.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(); } } 

现在有一个jacksonhibernate数据types库在这里:

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

你可以configuration这些function:

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