@ManyToOne 引用的 getId() 上的 LazyInitializationException
LazyInitializationException on getId() of a @ManyToOne reference
当我尝试访问分离实体的惰性 @ManyToOne 引用的 ID 时,我遇到了 LazyInitializationException
。我不想完全获取引用,但只需要 ID(它应该存在于原始对象中以便以 lazy/deferred 方式获取引用)。
EntityA ea = dao.find(1) // find is @Transactional, but transaction is closed after method exits
ea.getLazyReference().getId() // here is get exception. lazyReference is a ManyToOne relation and so the foreight key is stored in EntityA side.
换句话说,我如何在不实际获取整个 LazyReference 的情况下访问 LazyReference 的 ID(实际上存在于 EntityA 的初始 select 中)?
这应该是可能的。我只能获得 @ManyToOne
LAZY 实体的 ID。
但是为此,我在实体的 getter 上设置了注释,而不是直接在导致空值的实例变量上设置注释。
我相信您在实例变量上使用了注释。您可以尝试 getter 注释,看看是否对您有帮助。
你得到一个 LazyInitializationException
异常,因为 Hibernate 用代理对象包装了你的持久化对象。代理为惰性对象的任何 getter 生成异常,即使对于 LazyReference
已经具有的 id
当然也是如此。
要在没有 LazyInitializationException
的情况下获得 id
,您可以使用 this method(您可以参考 link 了解其他有趣的实用方法)
@SuppressWarnings("unchecked")
public static <T> T getPid(Persistent<?> persistent) {
if (persistent == null) {
return null;
}
if (!(persistent instanceof HibernateProxy) || Hibernate.isInitialized(persistent)) {
return (T) persistent.getPid();
}
LazyInitializer initializer = ((HibernateProxy) persistent).getHibernateLazyInitializer();
return (T) initializer.getIdentifier();
}
Persistent
是所有持久化对象的基础 class。对于您的 LazyReference
,您可以像这样重写代码
@SuppressWarnings("unchecked")
public static Long getId(LazyReference persistent) {
if (persistent == null) {
return null;
}
if (!(persistent instanceof HibernateProxy) || Hibernate.isInitialized(persistent)) {
return persistent.getId();
}
LazyInitializer initializer =
((HibernateProxy) persistent).getHibernateLazyInitializer();
return initializer.getIdentifier();
}
当使用字段访问时,Hibernate 将 getId()
方法与任何其他方法一样对待,这意味着调用它会触发代理初始化,因此如果在分离实例上调用会导致 LazyInitializationException
。
要仅对 ID 属性 使用 属性 访问权限(同时保留所有其他属性的字段访问权限),请为 ID 字段指定 AccessType.PROPERTY
:
@Entity
public class A {
@Id
@Access(AccessType.PROPERTY)
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
当我尝试访问分离实体的惰性 @ManyToOne 引用的 ID 时,我遇到了 LazyInitializationException
。我不想完全获取引用,但只需要 ID(它应该存在于原始对象中以便以 lazy/deferred 方式获取引用)。
EntityA ea = dao.find(1) // find is @Transactional, but transaction is closed after method exits
ea.getLazyReference().getId() // here is get exception. lazyReference is a ManyToOne relation and so the foreight key is stored in EntityA side.
换句话说,我如何在不实际获取整个 LazyReference 的情况下访问 LazyReference 的 ID(实际上存在于 EntityA 的初始 select 中)?
这应该是可能的。我只能获得 @ManyToOne
LAZY 实体的 ID。
但是为此,我在实体的 getter 上设置了注释,而不是直接在导致空值的实例变量上设置注释。
我相信您在实例变量上使用了注释。您可以尝试 getter 注释,看看是否对您有帮助。
你得到一个 LazyInitializationException
异常,因为 Hibernate 用代理对象包装了你的持久化对象。代理为惰性对象的任何 getter 生成异常,即使对于 LazyReference
已经具有的 id
当然也是如此。
要在没有 LazyInitializationException
的情况下获得 id
,您可以使用 this method(您可以参考 link 了解其他有趣的实用方法)
@SuppressWarnings("unchecked")
public static <T> T getPid(Persistent<?> persistent) {
if (persistent == null) {
return null;
}
if (!(persistent instanceof HibernateProxy) || Hibernate.isInitialized(persistent)) {
return (T) persistent.getPid();
}
LazyInitializer initializer = ((HibernateProxy) persistent).getHibernateLazyInitializer();
return (T) initializer.getIdentifier();
}
Persistent
是所有持久化对象的基础 class。对于您的 LazyReference
,您可以像这样重写代码
@SuppressWarnings("unchecked")
public static Long getId(LazyReference persistent) {
if (persistent == null) {
return null;
}
if (!(persistent instanceof HibernateProxy) || Hibernate.isInitialized(persistent)) {
return persistent.getId();
}
LazyInitializer initializer =
((HibernateProxy) persistent).getHibernateLazyInitializer();
return initializer.getIdentifier();
}
当使用字段访问时,Hibernate 将 getId()
方法与任何其他方法一样对待,这意味着调用它会触发代理初始化,因此如果在分离实例上调用会导致 LazyInitializationException
。
要仅对 ID 属性 使用 属性 访问权限(同时保留所有其他属性的字段访问权限),请为 ID 字段指定 AccessType.PROPERTY
:
@Entity
public class A {
@Id
@Access(AccessType.PROPERTY)
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}