在JPA懒惰列表上流

时间:2016-06-20 14:56:47

标签: java jpa java-8 eclipselink java-stream

我有JPA实体,列表如下:

@OneToMany(mappedBy = "scadaElement", orphanRemoval = true)
private List<ElementParameter> elementParameters;

并映射表单ElementParameter

@ManyToOne
@JoinColumn(name = "SCADAELEMENT_ID")
ScadaElement scadaElement;

当我获得带有elementParameters列表的实体并对其执行流时,即使我使用.size()触发列表时,也不执行任何操作,但是当我使用for循环执行相同操作时,它可以正常工作。

System.out.println("elements size: " + s.getElementParameters().size());
s.getElementParameters()
            .stream()
            .forEach(
                    a -> { 
                        System.out.println("elementId: " + a.getId());
                    }
            );

是否有任何解决方案可以使该流有效?我使用eclipselink作为JPA提供者。

2 个答案:

答案 0 :(得分:6)

显然,你指的是this issue。这些使用从实际实现继承的反模式(此处为Vector)的惰性列表无法适应基类的演变。请注意,根据反模式的实现方式,有两种可能的结果

  • 如果在第一次使用时,延迟填充的列表会填充自身(它是继承状态的条款),新的继承方法将在第一次访问触发器属性时立即开始工作
  • 但是如果列表覆盖了所有访问器方法以强制委派给另一个实现,而没有更新基类的状态,那么未被覆盖的基类的方法永远不会开始工作,即使列表已经填充(从子类的角度来看)

显然,第二种情况适用于您。触发列表的填充不会使继承的forEach方法起作用。请注意,通过配置关闭延迟填充可能是更简单的解决方案。

对我而言,最简洁的解决方案是IndirectList继承自AbstractList并遵守Collection API标准,现在,在Collection API取代Vector差不多20年后(应该我提到JPA实际上有多少年了?)。不幸的是,开发人员没有走那条路。相反,反模式通过创建另一个继承自已继承自未设计用于继承的类的类的类来最大化。该类重写了Java 8中引入的方法,并且可能在下一个Java发行版中获得另一个子类。

所以好消息是,开发人员希望每个List成为Vector都不必下定决心,但坏消息是it doesn’t work,有时,你不会使用JPA 2.6获得扩展的Java 8特定版本。但显然,JPA 2.7将起作用。

所以你可以推导出一些替代解决方案:

  • 关闭懒惰人口
  • 坚持使用Java 7
  • 等待JPA 2.7
  • 只需复制集合,例如
    List<ElementParameter> workList=new ArrayList<>(elementParameters);
    这个workList将支持所有收藏和收集。流操作

答案 1 :(得分:0)

为什么不使用real JPA Streaming

Stream<User> findAllByName(String name);