find()与EAGER @ElementCollection上的Hibernate LazyInitializationException [英] Hibernate LazyInitializationException on find() with EAGER @ElementCollection

查看:165
本文介绍了find()与EAGER @ElementCollection上的Hibernate LazyInitializationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我收到 org.hibernate.LazyInitializationException:在我的JPA代码中非法访问加载集合 - 所有集合都是EAGER fetch - 集合实体也具有集合时。



有人可以帮我解决这个问题吗?

我的JPA代码中存在一个问题, @Entity 定义:



(注意,我跳过了包和导入语句以缩短代码。一些Lombok注解被使用,例如@Data意味着该字段有一个getter / setter和@Cleanup来执行通常的try / catch close()跳舞)

<$ p
$ @ b $ b @ Data
public class MyEntity实现Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
私人长ID;

// @ElementCollection(fetch = FetchType.EAGER)
// private Set< String> tags = Sets.newTreeSet();

$ b $实体
@Data
公共类MyOtherEntity实现Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
私人长ID;

@ManyToMany(fetch = FetchType.EAGER)
private Set< MyEntity> entities = Sets.newHashSet();

$ / code $ / pre

(我也遇到同样的问题,如果我明确地执行完整的 @JoinTable ,但是Hibernate似乎在没有它的情况下生成了一切正常的东西 - 我很高兴把它遗留下来)。



问题是如果我取消注释 @MyEntity 中的tags字段,那么我总是得到以下 PersistenceException

 线程main中的异常javax.persistence.PersistenceException:org.hibernate.LazyInitializationException:非法访问加载集合
at org。 hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:828)
at org.hibernate.ejb.AbstractEntityManagerImpl.find( AbstractEntityManagerImpl.java:781)

下面是一个简短的应用程序,它解释了这个问题:

  public class JpaQuestion {
public static void main(String [] args)throws Exception {
Properties properties = new Properties();
properties.put(hibernate.connection.driver_class,org.apache.derby.jdbc.EmbeddedDriver);
properties.put(hibernate.connection.url,jdbc:derby:playground; create = true);
EntityManagerFactory emf = Persistence.createEntityManagerFactory(PlaygroundPU,properties);

填充(emf);

@Cleanup(close)EntityManager em = emf.createEntityManager();
MyOtherEntity other = em.find(MyOtherEntity.class,1L);
System.out.println(other!= null?other.toString():null);

$ b $ public static void populate(EntityManagerFactory emf){
@Cleanup(close)EntityManager em = emf.createEntityManager();
em.getTransaction()。begin();
MyEntity a = new MyEntity();
em.persist(a);
MyOtherEntity other = new MyOtherEntity();
other.getEntities()。add(a);
em.persist(other);
em.getTransaction()。commit();
}
}

更新:我知道 load()抓取实体的一个懒惰版本。我在这里使用查找。我注意到,如果我发出JPA查询(而不是查找),那么这个问题就会消失。



更新:如果不是 find(),我使用一个类似于的查询SELECT b FROM MyOtherEntity b WHERE b.id =:id。也许 find()确实会忽略 EAGER 加载!因此,这可能是Hibernate中的一个错误。



更新:我已经用Hibernate在 https://hibernate.onjira.com/browse/HHH-7476

解决方案

首先,引用完整的堆栈跟踪很有用: http://pastie.org/4358203



问题是由于您在MyEntity的hashCode()实现中对tags.hashCode()的调用所致。



当您使用Hibernate加载MyOtherEntity实例时,它将初始化MyEntity的集合。当MyEntity被添加到MyOtherEntity中的Set实现中时,它的hashCode()方法自然被调用(集合不能包含重复记录,而hashCode()是Java如何检查对象相等性的一部分)。 MyEntity的hashCode()方法然后尝试在标签集合上调用hashCode()。标签集合正处于初始化过程中,这会导致您出现此错误。



我认为值得考虑一下MyEntity的hashCode()实现。您的用例是否确实需要您比较标记集合中所有元素的值以确保对象相等?



有关在Hibernate中管理对象相等性的更多信息,以下是一个有用的资源:



https://community.jboss。 org / wiki / EqualsAndHashCode


I am getting org.hibernate.LazyInitializationException: illegal access to loading collection in my JPA code - all collections are EAGER fetch - when the collection entity also has a collection.

Could somebody please help me to fix this?

I have isolated a problem in my JPA code to the following @Entity definitions:

(note, I'm skipping the package and import statements to shorten the code. Some Lombok annotations are used, such as @Data to mean that the field has a getter/setter and @Cleanup to do the usual try/catch close() dance)

@Entity
@Data
public class MyEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

//    @ElementCollection(fetch = FetchType.EAGER)
//    private Set<String> tags = Sets.newTreeSet();
}

@Entity
@Data
public class MyOtherEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToMany(fetch = FetchType.EAGER)
    private Set<MyEntity> entities = Sets.newHashSet();
}

(I also get the same problem if I explicitly do a full @JoinTable, but Hibernate seems to generate everything fine without it - I'm happy leaving it out).

The problem is that if I uncomment the "tags" field in @MyEntity, then I always get the following PersistenceException

Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.LazyInitializationException: illegal access to loading collection
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
    at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:828)
    at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:781)

The following is a short application which exemplifies the problem:

public class JpaQuestion {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.put("hibernate.connection.driver_class", "org.apache.derby.jdbc.EmbeddedDriver");
        properties.put("hibernate.connection.url", "jdbc:derby:playground;create=true");
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PlaygroundPU", properties);

        populate(emf);

        @Cleanup("close") EntityManager em = emf.createEntityManager();
        MyOtherEntity other = em.find(MyOtherEntity.class, 1L);
        System.out.println(other != null ? other.toString() : "null");
    }

    public static void populate(EntityManagerFactory emf) {
        @Cleanup("close") EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        MyEntity a = new MyEntity();
        em.persist(a);
        MyOtherEntity other = new MyOtherEntity();
        other.getEntities().add(a);
        em.persist(other);
        em.getTransaction().commit();
    }
}

UPDATE: I know about LazyInitializationException when field is eager but that seems to be because load() grabs a lazy version of the entity. I'm using "find" here. I've noticed that if I issue a JPA query (instead of find), then this problem goes away.

UPDATE: This really does work fine if instead of find(), I use a Query like "SELECT b FROM MyOtherEntity b WHERE b.id = :id". Maybe find() really does ignore EAGER loading! Hence this is likely a bug in Hibernate.

UPDATE: I've logged this as a bug report with Hibernate at https://hibernate.onjira.com/browse/HHH-7476

解决方案

First of all it is useful to reference the full stack trace: http://pastie.org/4358203

The problem is being caused by your call to tags.hashCode() within the hashCode() implementation of MyEntity.

When you use Hibernate to load the MyOtherEntity instance, it's collection of MyEntity is initialised. When a MyEntity is added to the Set implementation within MyOtherEntity, it's hashCode() method is naturally called (sets cannot contain duplicates remember and hashCode() is part of how Java checks for object equality). The hashCode() method of MyEntity then attempts to invoke hashCode() on the tags collection. The tags collection is in the process of being initialised, which leads you to this error.

I think it is worth thinking about your hashCode() implementation for MyEntity. Does your use-case really require you to compare the value of the all elements within the tags collection to ensure object equality?

For more information on managing object equality in Hibernate, the following is a useful resource:

https://community.jboss.org/wiki/EqualsAndHashCode

这篇关于find()与EAGER @ElementCollection上的Hibernate LazyInitializationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆