在JSF支持bean中有关联的独立JPA实体
在我当前的项目中,我们使用JSF 2.2,JPA 2(Hibernate作为持久性提供者)和Spring Data JPA。在JSF支持bean中有关联的独立JPA实体
的情况是这样的,我试图简化尽可能:我们有一个实体类Car
有双向关系Extra
,一个Car
引用多个Extra
实例。
public class Car {
// ...
@OneToMany(mappedBy = "car", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<Extra> extras;
// ...
}
Extra
不仅包含单个String
属性和向后引用Car
。
在用于编辑单辆汽车及其附加件的后台bean中,我们有这样的情况,我们希望将bean的状态保持在视图范围内(对此,我们有一个自定义的@ViewScope
基于Spring的注释,它具有与JEE的@ViewScoped
相同的行为)。
我们采取的方法基本上将Car
实例直接存储在backing bean中。 CarRepository
是一个Spring数据存储库。
的Car
实例被直接引用,并在相关的* .xhtml文件从某些JSF相关的标记约束。
但是,Car
实例在第一个请求后被分离。现在让我们考虑在相同的视图中,有一种方法可以将Extra
实例添加到Car
实例。也许现有的可以修改和删除。
在多个请求之间的相同页面上修改与其他实体之间的关系的分离JPA实体,直到它们被显式保存时,JSF项目遵循的最佳实践是什么? (请考虑extras
是一个懒惰的集合,所以当这个集合没有被加载和访问时,比方说,在第二个请求中,会抛出一个异常。但是,为新的/修改/删除的实例保留列表Extra
实例在代码复杂性方面也感觉有点太多)。
这种情况总是难以管理。我想你是懒惰地加载Extra
集合的情况下,你列出Cars
,而不是加载所有的汽车与他们的临时演员。你有很多的解决方案:
使额外的集合被急切加载并限制显示列表时加载的汽车数量。这样你就可以在bean中获得额外的功能。
实现一种方法来返回每辆车的额外列表。通过这种方式,您可以删除与汽车实体本身的关系,并且可以单独处理每个额外的视图,只保留一个包含当前附加信息(可以带有ID或不带有ID)的集合,以及用于删除的附加信息。保存版本时,请调用您需要更新附加功能的服务方法。
你甚至可以从视图抽象这一点,如果你做这样的服务(考虑到你一直留有一个车以其演员):
@Transactional
public Car save(Car car, Collection<Extra> assignedExtras){
Car result = carRepo.save(car);
List<Extra> savedExtras = extraRepo.findByCar(car);
for (Extra extra : assignedExtras){
extra.setCar(car);
extraRepo.save(extra);
savedExtras.remove(extra);
}
//Here, savedExtras contains only the extras you have removed, so let's remove them
for (Extra extra : savedExtras){
extraRepo.delete(extra);
}
return result;
}
- 使用Entity Graphs,从JPA 2.1开始:
延迟加载经常使用JPA 2.0的一个问题。您必须在实体中定义是否要使用FetchType.LAZY(默认)或FetchType.EAGER加载关系,并始终使用此模式。 FetchType.EAGER仅用于我们总是加载关系的情况。几乎在所有情况下都使用FetchType.LAZY来获得性能良好且可伸缩的应用程序。 但这不是没有缺点。如果必须使用关系的元素,则需要确保关系在从数据库加载实体的事务内初始化。这可以通过使用从数据库中读取实体和所需关系的特定查询来完成。但是这会导致用例特定的查询。另一个选择是访问业务代码中的关系,这将导致每个关系的附加查询。两种方法都远非完美。
JPA 2.1实体图是一个更好的解决方案。实体图的定义与查询无关,并定义要从数据库中提取哪些属性。实体图可以用作提取或加载图。如果使用提取图表,则只有实体图表指定的属性将被视为FetchType.EAGER。所有其他属性将是懒惰的。如果使用加载图,则实体图未指定的所有属性将保持其默认提取类型。
感谢您的评论。我担心答案会朝着这个方向发展;-)感谢您提及JPA 2.1实体图,这是我监督的事情。我们将通过Spring Data的@EntityGraph进行调查以找到一种可能使用渴望获取的方式。 –
隐藏从哪个开发者?如果你在“服务层”中进行所有合并,UI开发人员永远不需要知道这一切...... – Kukeltje
@Kukeltje感谢您的评论。这个问题的目标是回答这些情况下的最佳实践。最后一句话可能会导致另一个方向,所以我删除了它。 –
'最佳实践'问题在*上并不是很好的问题,因为他们倾向于自以为是。但是,imo ...'隐藏在服务中'。谷歌有点'扩展持久性''开放会议在视图中'和阅读相关主题... – Kukeltje