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