2017-09-26 115 views
0

在我当前的项目中,我们使用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实例在代码复杂性方面也感觉有点太多)。

+1

隐藏从哪个开发者?如果你在“服务层”中进行所有合并,UI开发人员永远不需要知道这一切...... – Kukeltje

+0

@Kukeltje感谢您的评论。这个问题的目标是回答这些情况下的最佳实践。最后一句话可能会导致另一个方向,所以我删除了它。 –

+0

'最佳实践'问题在stackoverflow上并不是很好的问题,因为他们倾向于自以为是。但是,imo ...'隐藏在服务中'。谷歌有点'扩展持久性''开放会议在视图中'和阅读相关主题... – Kukeltje

回答

1

这种情况总是难以管理。我想你是懒惰地加载Extra集合的情况下,你列出Cars,而不是加载所有的汽车与他们的临时演员。你有很多的解决方案:

  1. 使额外的集合被急切加载并限制显示列表时加载的汽车数量。这样你就可以在bean中获得额外的功能。

  2. 实现一种方法来返回每辆车的额外列表。通过这种方式,您可以删除与汽车实体本身的关系,并且可以单独处理每个额外的视图,只保留一个包含当前附加信息(可以带有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。所有其他属性将是懒惰的。如果使用加载图,则实体图未指定的所有属性将保持其默认提取类型。

    +0

    感谢您的评论。我担心答案会朝着这个方向发展;-)感谢您提及JPA 2.1实体图,这是我监督的事情。我们将通过Spring Data的@EntityGraph进行调查以找到一种可能使用渴望获取的方式。 –

    相关问题