【发布时间】:2011-09-15 07:19:19
【问题描述】:
想听听专家关于从 JSF UI 编辑 JPA 实体的最佳实践。
所以,关于这个问题的几句话。
想象一下,我有一个持久化对象MyEntity,我获取它进行编辑。在 DAO 层我使用
return em.find(MyEntity.class, id);
它返回 MyEntity 实例,代理在“父”实体上 - 想象其中一个是 MyParent。 MyParent 被提取为@Access(AccessType.PROPERTY) 的代理问候语:
@Entity
public class MyParent {
@Id
@Access(AccessType.PROPERTY)
private Long id;
//...
}
并且 MyEntity 有对它的引用:
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.PROXY)
private MyParent myParent;
到目前为止一切顺利。在 UI 中,我只是直接使用获取的对象而不创建任何值对象,并在选择列表中使用父对象:
<h:selectOneMenu value="#{myEntity.myParent.id}" id="office">
<f:selectItems value="#{parents}"/>
</h:selectOneMenu>
一切正常,没有出现LazyInitializationException。但是当我保存对象时,我收到了
LazyInitializationException: could not initialize proxy - no Session
在MyParent代理setId()方法上。
如果我将MyParent 关系更改为EAGER,我可以轻松解决问题
@ManyToOne(fetch = FetchType.EAGER)
private MyParent myParent;
或使用left join fetch p.myParent 获取对象(实际上我现在就是这样做的)。在这种情况下,保存操作正常,并且关系透明地更改为新的MyParent 对象。无需执行其他操作(手动复制、手动参考设置)。非常简单方便。
但是。如果对象引用了 10 个其他对象 - em.find() 将导致 10 个额外的连接,这不是一个好的数据库操作,尤其是当 我根本不使用引用对象状态时。我所需要的只是指向对象的链接,而不是它们的状态。
这是一个全球性问题,我想知道 JSF 专家如何在其应用程序中处理 JPA 实体,这是避免额外连接和LazyInitializationException 的最佳策略。
扩展持久性上下文不适合我。
谢谢!
【问题讨论】:
-
您能做的最好的事情是在将实体处理为 JSF bean 之前重新映射/深度克隆实体。
-
@DanubianSailor 我希望看到完整的答案,并解释该建议的利弊。我目前也在考虑同样的事情。
-
您使用的是什么版本的 JavaEE(EJB、CDI、JSF)?
标签: hibernate jsf jpa lazy-initialization