通过JPA / Hibernate方法访问@Id字段时阻止代理初始化

时间:2012-10-19 08:08:05

标签: java hibernate jpa

我想让我的实体实现某个接口,返回id:

public interface IdentifiableEntity<T extends Comparable<T>> {
    public T getIdentifier();
}

但是如果我这样做并且实体是延迟加载的,getIdentifier()初始化代理(并导致单独的选择)。这是一个示例实体:

@Entity
public class AppFile implements IdentifiableEntity<Long> {

    @Id
    @GeneratedValue
    private Long id;

    public Long getIdentifier() {
        return id;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    ...

}

有没有办法告诉Hibernate / JPA getIdentifier()只访问众所周知的ID而不需要初始化代理?

我已经找到了:

  1. 当我注释属性(getter)而不是所有字段时,getId()将不会初始化代理。
  2. @Access(AccessType.PROPERTY)上使用private Long id;,它将表现为1.无需在属性级别注释所有内容。
  3. 更新 1.和2.都不满足我的要求,即:

    • getIdentifier()返回没有代理初始化的ID
    • 字段id不会更改其名称(因为有很多现有的JPQL语句)。

3 个答案:

答案 0 :(得分:0)

getId()方法初始化代理,只需要重定向getIdentifier()方法。

public Long getId() {
    return getIdentifier();
}

答案 1 :(得分:0)

即使您在字段上使用注释,也可以使用Java Reflection API直接访问id值。在这里,我使用org.easytesting fest-reflect API(Reflection API的一个薄包装器)来缩短代码。 proxy.handler.id下的id值。 我的示例是具有ManyToOne到部门(潜在代理)的员工。 就我而言,id(s)总是很长......

public Long extractIdFromDepartment(Employee employee) {

    Long idDepartment = null;

    Department departement = employee.getDepartment();
    Boolean isNotProxy = Persistence.getPersistenceUtil().isLoaded(departement);

    if (isNotProxy) {
        // here, department is not a proxy
        // a direct access is always ok
        idDepartment = departement.getId();
    } else {
        // here department IS a proxy
        // works in all cases : with Hibernate/JPA annotations on getters or fields.
        javassist.util.proxy.MethodHandler handler = Reflection.field("handler")
                .ofType(javassist.util.proxy.MethodHandler.class).in(departement).get();
        java.io.Serializable idDep = Reflection.field("id").ofType(java.io.Serializable.class).in(handler).get();
        if (idDep instanceof Long) {
            idDepartment = (Long) idDep;
        }
    }
    return idDepartment;
}

答案 2 :(得分:0)

那么4年后,但这将是解决方案:

@Entity @Access(AccessType.FIELD) 公共类AppFile实现IdentifiableEntity {

@Id
@GeneratedValue
@Access(AccessType.PROPERTY)
private Long id;


   public Long getId(){
       return id; 
   }

现在在实体上调用getId()将不会初始化其代理。