LazyInitializationException on getId() of a @ManyT

2019-09-11 13:20发布

问题:

I'm facing LazyInitializationException when I'm trying to access ID of a lazy @ManyToOne reference of a detached entity. I do not want to fetch the refrence completely, but just need the ID (which should be exist in original object in order to fetch refrence in a lazy/deferred manner).

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.

To paraphrase, how can I access ID of LazyReference (which actually exists in initial select for EntityA) without actually fetching the whole LazyReference?

回答1:

When field access is used, Hibernate treats getId() method the same as any other method, meaning that calling it triggers proxy initialization, thus leading to LazyInitializationException if invoked on a detached instance.

To use property access only for id property (while keeping field access for all the other properties), specify AccessType.PROPERTY for the id field:

@Entity
public class A {
  @Id
  @Access(AccessType.PROPERTY)
  private int id;

  public int getId() {
    return id;
  }

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


回答2:

That should be possible. I am able to get only the ID of the @ManyToOne LAZY entity.

But for that I have set annotations on the getters of the entity instead of setting them directly on the instance variables which results in null value.

I believe you are using annotations on the instance variables. You can try getter annotations and see if that helps you.



回答3:

You get an LazyInitializationException exception, because of Hibernate wraps your persistent with a proxy object. A proxy generates an exception for any getter of a lazy object even for id that LazyReference already has of course.

To get id without LazyInitializationException you can use this method (you can refer the link for other interesting utilite methods)

@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 is a base class for all persistents. For your LazyReference you can rewrite code like this

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