在JSF支持bean

时间:2017-09-26 11:58:38

标签: jsf jpa spring-data-jpa jsf-2.2

在我目前的项目中,我们使用JSF 2.2,JPA 2(Hibernate作为持久性提供程序)和Spring Data 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&#39; s @ViewScoped具有相同的行为。

我们采取的方法基本上将Car实例直接存储在辅助bean中。 CarRepository是一个Spring Data存储库。

@Component
@ViewScope
public class CarEditView {

    @Getter @Setter
    private Integer id;

    @Autowired
    private CarRepository carRepository;

    @Getter
    private Car car;

    public void load() {
        car = carRepository.findOne(id);
    }

    public void save(){
        carRepository.save(car);
    }

    // ...

Car实例直接引用并绑定到相关* .xhtml文件中某些与JSF相关的标记。

但是,Car实例在第一个请求后会分离。现在让我们在同一视图中考虑将Extra实例添加到Car实例的方法。也许现有的可以修改和删除。

在多个请求之间在同一页面上修改与其他实体有关系的分离的JPA实体,直到它们被明确保存为止,JSF项目遵循的最佳做法是什么?

(请注意extras是一个惰性集合,所以当没有加载和访问此集合时,请说,在第二个请求中,将抛出异常。但是,保留列表新的/修改的/删除的Extra实例在代码复杂性方面也感觉有点过分。)

1 个答案:

答案 0 :(得分:1)

这种情况总是难以管理。我认为你懒得加载Extra集合,用于列出Cars的情况,而不是加载所有汽车的额外内容。你有很多解决方案:

  1. 急切加载额外的集合,并在显示列表时限制正在加载的汽车数量。这样你就可以在你的bean中使用额外的东西了。

  2. 实施一种方法来返回每辆车的额外列表。通过这种方式,您可以删除与car实体本身的关系,并且您可以单独处理每个额外的内容,对于视图,只需保留一个包含当前附加内容(可以具有id或不具有id)的集合,以及其他用于删除的附加内容。保存版本时,请调用更新附加内容所需的服务方法。

  3. 如果你在服务中这样做,你甚至可以从视图中抽象出来(考虑到你总是用额外的东西保存汽车):

    @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;
    }
    
    1. 从JPA 2.1开始使用Entity Graphs
    2.   

      延迟加载通常是JPA 2.0的一个问题。您必须在实体上定义是否要使用FetchType.LAZY(默认值)或FetchType.EAGER来加载关系,并始终使用此模式。仅当我们想要始终加载关系时才使用FetchType.EAGER。几乎在所有情况下都使用FetchType.LAZY来获得性能良好且可伸缩的应用程序。   但这并非没有缺点。如果必须使用关系的元素,则需要确保在从数据库加载实体的事务中初始化关系。这可以通过使用从数据库读取实体和所需关系的特定查询来完成。但这将导致特定于用例的查询。另一种选择是访问业务代码中的关系,这将导致对每个关系的附加查询。这两种方法都远非完美。

           

      JPA 2.1实体图是更好的解决方案。实体图的定义独立于查询,并定义从数据库中提取的属性。实体图可以用作提取或加载图。如果使用了获取图,则只有实体图指定的属性才会被视为FetchType.EAGER。所有其他属性都是懒惰的。如果使用加载图,则实体图未指定的所有属性将保留其默认的提取类型。