CDI + JPA 多个 @OneToMany - LAZY/EAGER - LazyInitializationException 或无法实例化多个包

Posted

技术标签:

【中文标题】CDI + JPA 多个 @OneToMany - LAZY/EAGER - LazyInitializationException 或无法实例化多个包【英文标题】:CDI + JPA Multiple @OneToMany - LAZY/EAGER - LazyInitializationException OR Cannot instantiate multiple bags 【发布时间】:2013-05-13 17:09:29 【问题描述】:

我正在使用 Jboss AS 7、CDI、JPA 和其他一些捆绑资源开发应用程序。

我的问题是:当我在 Eclipse 中使用 maven-jboss-webapp-archetype 创建一个项目时,它会生成一些文件,我一直在广泛研究并试图与之相处。问题是,有时我觉得自己是在使用 Hibernate 资源还是 JPA 资源有点困惑。

第二个问题:当我在同一个实体中使用多个 @OneToMany 关系时,我注意到两种行为:

a) 如果没有为 Fetch 指定 EAGER 类型,它会部署应用程序,但是当我尝试使用该列表时,它给了我 LazyInitializationException 错误,因此在这里进行了广泛讨论。

b) 当我在 @*ToMany 关系上为 FetchType 指定 Eager 时,它只是不部署应用程序。它给了我错误:无法实例化多个包。

这是有问题的代码:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "teamUser" , fetch = FetchType.EAGER)
private Collection<Users> usersCollection;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "teamRanking" , fetch = FetchType.LAZY)
private Collection<Ranking> rankingCollection;

@NotNull
@OneToMany(cascade = CascadeType.ALL, mappedBy = "teamModality" , fetch = FetchType.LAZY)
private Collection<Modality> modalitiesCollection;

public Teams() 



public Teams(Long id_team , String name) 
    this.id = id_team;
    this.name = name;

我一直在阅读这方面的内容,人们告诉我 JPA 不支持 FetchType.EAGER 用于同一实体中的多个关系。但是我需要在这个实体中具体使用多个关系。我不知道该怎么办了,因为我尝试了几种方法,Lazy fetching,所有这些方法都存在某种问题。例如,如果我在课堂上只留下一个 FetchType.EAGER,那么它会部署我的应用程序,但它无法正常运行,因为当我尝试从数据库中获取列表时,它会给我错误:LazyInitializationException,当我尝试使用 FetchType.EAGER 将它们全部放入时,它只是没有部署,因为它给出了错误:无法实例化多个包。

所以我这里的问题与:

1) Maven-jboss-webapp-archetype 使用 hibernate 或 jpa 还是两者兼而有之? 2)如何解决在实体中使用多个@OneToMany 关系的问题?尽管我知道急切地获取模型中的集合并不是最好的方法,因为当系统增长时,我可能会遇到性能问题,对吧?那么如何才能正确使用延迟加载呢?

【问题讨论】:

您使用的是什么 JPA 实现?休眠? 是的,我使用的是捆绑在 JBoss AS 7 中的 hibernate,我认为它是 Hibernate 4。感谢您的回答 John 你可能应该看看这个 SO 作为参考:***.com/questions/10769656/… 它使用 Hibernate 特定的注释,但可以做你需要的。 【参考方案1】:

首先,Hibernate 是 JPA 规范的一种实现,是 JBoss 中的默认实现。因此,您使用的是 JPA,并使用 Hibernate 作为实现。

其次,您会得到一个 LazyInitialization 异常,因为您在关闭会话后访问了一个延迟加载的集合,而在会话仍处于打开状态时没有初始化此集合。如果您有两个惰性集合并且您知道客户端代码都需要初始化,请在返回实体和关闭会话之前初始化它们(即当您仍在事务服务方法中时):

SomeEntity e = em.find(SomeEntity.class, someId);
e.getFirstCollection().size(); // initialize the first collection
e.getSecondCollection().size(); // initialize the second collection
return e;

您可以一次获取多个 toMany 关联,但其中只有一个可以是包(即集合或列表)。我一般不建议急切的收藏。但是,如果您真的想要它们,请将它们设置为集合而不是集合。

【讨论】:

JB Nizet 非常感谢您的解释。这让事情变得更加清晰。你能看看我的DAO方法之一吗?因为我不知道您所说的事务服务方法到底是什么意思。因为我没有使用诸如 commit 之类的方法从数据库中检索数据。 [code] public List retrieveAllMembersOrderedByName() List teams = null; CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery 条件 = cb.createQuery(Teams.class); Root 成员 = criteria.from(Teams.class); criteria.select(member).orderBy(cb.asc(member.get(Member_.name))); criteria.select(member).orderBy(cb.asc(member.get("name")));团队 = em.createQuery(criteria).getResultList();返回团队; 如果您想添加代码,请编辑您的问题。您必须使用事务来访问实体管理器。在 Java EE 环境中,例如部署在 JBoss 上并使用 CDI 的应用程序,这就像使用 @Stateless 注释的服务类一样简单,这使其成为会话 EJB。默认情况下,EJB 是事务性的。

以上是关于CDI + JPA 多个 @OneToMany - LAZY/EAGER - LazyInitializationException 或无法实例化多个包的主要内容,如果未能解决你的问题,请参考以下文章

onetomany 单向与使用 jpa 的可连接设置

Spring JPA OneToMany 集合不删除条目

在 Java SE 中拥有 CDI 和 JPA 的最简单方法是啥?

如何将 JPA 验证与 CDI 和 Seam 验证集成

Spring data jpa @OneToMany 在一的一端进行查询()对集合属性设置条件查询)

不加入子表的 JPA (@OneToMany) 查询