我最近听到人们说数据传输对象(DTO)是一种反模式.
为什么?有哪些替代方案?
希望听听有关从JSF UI编辑JPA实体的最佳实践的专家.
所以,关于这个问题的几句话.
想象一下,我有持久化对象MyEntity
,我将其取出进行编辑.在DAO层我使用
return em.find(MyEntity.class, id);
Run Code Online (Sandbox Code Playgroud)
MyEntity
在"父"实体上返回带有代理的实例 - 想象其中一个是MyParent
.MyParent
被提取为代理问候语@Access(AccessType.PROPERTY)
:
@Entity
public class MyParent {
@Id
@Access(AccessType.PROPERTY)
private Long id;
//...
}
Run Code Online (Sandbox Code Playgroud)
和MyEntity有它的参考:
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.PROXY)
private MyParent myParent;
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.在UI中,我只是直接使用获取的对象而不创建任何值对象,并使用选择列表中的父对象:
<h:selectOneMenu value="#{myEntity.myParent.id}" id="office">
<f:selectItems value="#{parents}"/>
</h:selectOneMenu>
Run Code Online (Sandbox Code Playgroud)
一切都好,没有LazyInitializationException
发生.但是当我保存对象时,我收到了
LazyInitializationException: could not initialize proxy - no Session
Run Code Online (Sandbox Code Playgroud)
在MyParent
代理setId()
方法.
如果我改变MyParent
关系,我可以轻松解决问题EAGER
@ManyToOne(fetch = FetchType.EAGER)
private MyParent myParent;
Run Code Online (Sandbox Code Playgroud)
或使用获取对象left join fetch p.myParent
(实际上我现在这样做).在这种情况下,保存操作正常,并且关系MyParent
透明地更改为新对象.不需要执行其他操作(手动复制,手动参考设置).非常简单方便. …
我刚刚意识到,当一个对象从Hibernate的缓存驱逐,依赖集合,如果缓存,已被驱逐分开.
对我来说这是一个很大的WTF:
驱逐依赖集合的代码是丑陋和庞大的,例如
MyClass myObject = ...;
getHibernateTemplate().evict(myObject);
Cache cache = getHibernateTemplate().getSessionFactory().getCache();
cache.evictCollection("my.package.MyClass.myCollection1, id);
...
cache.evictCollection("my.package.MyClass.myCollectionN, id);
很明显,如果父对象发生了变化,那么保留它的集合几乎没有意义,因为它们最有可能是从父节点派生出来的.
我在这里错过了什么吗?如果没有手动编写所有这些代码,是否真的无法将对象与其所有子实体一起刷新?