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