将JPA、EJB和JSF托管bean结合的首选设计模式是什么?

4
这是一个设计模式问题。以下是场景: 我正在使用EJB3.0和JPA。例如,假设我有一个用户可以属于多个组。因此,在我的User实体中,我有一个获取组的方法getGroups(),它会懒加载。我还有一个UserDao,它是一个无状态会话bean,它有一个方法getUser(int uid)。
现在,在我的JSF后备bean中,我注入了UserDao的远程接口,并调用它的getUser方法来获取User bean。但是,我无法访问user.getGroups,因为它是一个分离的实体。因此,我可以考虑三种方法:
1. 在我的dao方法中,我急切地获取组,以便它们也可以在远程User实体中访问。但是这样做的问题是Group本身可能具有懒惰获取的关系,那么我也必须急切地获取它们,而这些关系可能还有更多的懒惰获取的关系,依此类推。因此,我最终会发送一个重量级对象,其中大部分属性我将不需要。
2. 我按原样发送User,并依赖于我的客户端不在其上调用getGroups。我可以在userdao中提供一个单独的方法,如下所示: List getGroupsIds(int userId) 我还有一个GroupDao,它有类似的方法getGroup(int groupId)和其他方法来获取懒惰关系的Ids。
3. 第三个选择是根本不发送这些JPA实体,并创建其他POJO,如UserInfo、GroupInfo等,它们只包含每个实体的基本属性并发送这些实体。我可以在DAO中编写方法来获取不同关系的这些实体,例如: List getGroupsForUser(int uid) List getUsersInGroup(int gid)
那么这些中哪一个是首选模式呢?还是有其他人在这里使用的模式吗?

3
我怀疑将它们平稳地整合的最简单方法是使用Seam:http://www.jboss.com/products/seam/ - skaffman
是的,就我所知,Seam可能是最好的选择,但现在我却无法使用它。 - Vikas Kedia
你是在特定的JPA实现上工作,还是只是一般性地询问。EclipseLink和Kodo都会按需加载它们。或者开发人员可以请求进行急切获取。 - Billy Bob Bain
3个回答

1

还有第四和第五个选项 :-)

4) 在相关的 API 调用中包含一个“通胀水平”参数,例如 getUser(id, inflationLevel)。这样,您将委托选择哪些通过网络发送的对象部分将可供使用该对象的客户端使用的责任。您可以将所述通胀水平设置得粗略或细粒度。典型示例可能是 BASIC(仅填充立即属性),ASSOCIATIONS(基本 + 直接集合/关联),FULL(整个层次结构 - 所有关联对象)。

5) 您可以编写自己的代理,支持通过网络的惰性初始化。如果您正在惰性加载的关联对象(或属性)可能非常庞大,但客户端相对较少使用,则此方法才可行。

当然,还有像 skaffman 提到的 Seam :-)


0

我目前的项目已经实现了第三个选项,但效果不佳。每次更改需要修改2-3个类,而不仅仅是一个。字段重复等问题也存在。这不是一个好的选择。

如果你真的不需要User对象可以主动获取的所有信息,那就选择第二个选项。

如果事实上你始终需要所有用户信息,并且没有其他人通过远程服务使用你的User对象,则使用你的User对象--选择第一个选项。

还有其他解决方案,我也需要更好的解决方案。


第二种方法的问题在于我要依靠我的客户端进行正确的调用,这是危险的。客户端不会知道不应该调用getGroups。 - Vikas Kedia
从公共访问中删除getGroups()。 - Mykola Golubyev
我认为这就是JPA(hibernate)的瓶颈所在。听起来很棒,但实际上你无法使用任何酷炫的功能。 - Mykola Golubyev

0
为什么用户实例被分离?如果您真的在使用JPA,可以使用活动实例。因此,当调用getGroups()时,用户组会被惰性加载。

它是分离的,因为在EJB容器管理的事务中,当您退出EJB方法时,事务结束,从而销毁持久上下文并分离由其管理的所有实体。 - Vikas Kedia
这要看情况。这里是文档中的一小段引用: “在Java EE环境中,jta-data-source和non-jta-data-source元素用于指定持久性提供程序使用的全局JNDI名称的JTA和/或非JTA数据源。” - Serge Bogatyrev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接