Java Hibernate 一对一:getId() 不获取整个对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2593722/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hibernate one-to-one: getId() without fetching entire object
提问by Rob
I want to fetch the id of a one-to-one relationship without loading the entire object. I thought I could do this using lazy loading as follows:
我想在不加载整个对象的情况下获取一对一关系的 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
I want f.getBar() to nottrigger another fetch. I want hibernate to give me a proxy object that allows me to call .getId() without actually fetching the Bar object.
我希望 f.getBar()不会触发另一个获取。我希望 hibernate 给我一个代理对象,它允许我调用 .getId() 而不实际获取 Bar 对象。
What am I doing wrong?
我究竟做错了什么?
采纳答案by Arthur Ronald
Use property access strategy
使用属性访问策略
Instead of
代替
@OneToOne(fetch=FetchType.LAZY, optional=false)
private Bar bar;
Use
用
private Bar bar;
@OneToOne(fetch=FetchType.LAZY, optional=false)
public Bar getBar() {
return this.bar;
}
Now it works fine!
现在它工作正常!
A proxy is initialized if you call any method that is not the identifier getter method. But it just works when using property access strategy. Keep it in mind.
如果您调用任何不是标识符 getter 方法的方法,则会初始化代理。但它只在使用属性访问策略时有效。记在心上。
回答by Bozhidar Batsov
You could use a HQL query. The getBar() method will truly return a proxy, that won't be fetched until you invoke some data bound method. I'm not certain what exactly is your problem. Can you give us some more background?
您可以使用 HQL 查询。getBar() 方法将真正返回一个代理,在您调用某些数据绑定方法之前不会获取该代理。我不确定你的问题到底是什么。你能给我们更多的背景吗?
回答by xmedeko
Just to add to the Arthur Ronald F D Garcia'post: you may force property access by @Access(AccessType.PROPERTY)
(or deprecated @AccessType("property")
), see http://256stuff.com/gray/docs/misc/hibernate_lazy_field_access_annotations.shtml
只是添加到 Arthur Ronald FD Garcia 的帖子:您可以通过@Access(AccessType.PROPERTY)
(或弃用@AccessType("property")
)强制访问属性,请参阅http://256stuff.com/gray/docs/misc/hibernate_lazy_field_access_annotations.shtml
Another solution may be:
另一种解决方案可能是:
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();
}
Works for detached entities, too.
也适用于分离的实体。
回答by Grégory
In org.hibernate.Session you have a function who do the work without lazy loading the entity :
在 org.hibernate.Session 中,您有一个功能可以在不延迟加载实体的情况下完成工作:
public Serializable getIdentifier(Object object) throws HibernateException;
public Serializable getIdentifier(Object object) 抛出 HibernateException;
Found in hibernate 3.3.2.GA :
在休眠 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();
}
}
回答by MarcG
The Java Persistence with Hibernate Book mentions this in "13.1.3 Understanding Proxies":
Java Persistence with Hibernate Book 在“13.1.3 理解代理”中提到了这一点:
As long as you access only the database identifier property, no initialization of the proxy is necessary. (Note that this isn't true if you map the identifier property with direct field access; Hibernate then doesn't even know that the getId() method exists. If you call it, the proxy has to be initialized.)
只要您只访问数据库标识符属性,就不需要初始化代理。(请注意,如果您使用直接字段访问映射标识符属性,则情况并非如此;Hibernate 甚至不知道 getId() 方法存在。如果您调用它,代理必须被初始化。)
However, based on @xmedeko answer in this page I developed a hack to avoid initializing the proxy even when using direct field access strategy. Just alter the getId()
method like shown below.
但是,基于此页面中的@xmedeko 回答,我开发了一个技巧,即使在使用直接字段访问策略时也能避免初始化代理。只需更改getId()
如下所示的方法即可。
Instead of:
代替:
public long getId() { return id; }
Use:
用:
public final long getId() {
if (this instanceof HibernateProxy) {
return (long)((HibernateProxy)this).getHibernateLazyInitializer().getIdentifier();
}
else { return id; }
}
The idea here is to mark the getId()
method as final
, so that proxies cannot override it. Then, calling the method cannot run any proxy code, and thus cannot initialize the proxy. The method itself checks if its instance is a proxy, and in this case returns the id from the proxy. If the instance is the real object, it returns the id.
这里的想法是将getId()
方法标记为final
,以便代理无法覆盖它。那么,调用该方法无法运行任何代理代码,从而无法初始化代理。该方法本身检查它的实例是否是代理,并在这种情况下从代理返回 id。如果实例是真实对象,则返回 id。
回答by Mohsen Kashi
change your getter method like this:
像这样改变你的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;
}
回答by Dima
add @AccessType("property")
添加@AccessType("属性")
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@AccessType("property")
protected Long id;
回答by chrismarx
There is now a Hymanson hibernate datatype library here:
现在这里有一个 Hymanson hibernate 数据类型库:
https://github.com/FasterXML/Hymanson-datatype-hibernate
https://github.com/FasterXML/Hymanson-datatype-hibernate
And you can configure the features:
您可以配置以下功能:
Hibernate4Module hibernate4Module = new Hibernate4Module();
hibernate4Module.configure(Hibernate4Module.Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS, true);
This will include the id of the lazy loaded relationship-
这将包括延迟加载关系的 id-
回答by Paul Wasilewski
Unfortunately the accepted answer is wrong. Also other answers doesn't provide the simplest or a clear solution.
不幸的是,接受的答案是错误的。其他答案也没有提供最简单或明确的解决方案。
Use the Property Access Level for the ID
of the BAR
class.
使用属性访问级别为ID
中的BAR
类。
@Entity
public class Bar {
@Id
@Access(AccessType.PROPERTY)
private Long id;
...
}
Just as simple as that :)
就这么简单:)