【问题标题】:stream on JPA lazy listJPA惰性列表上的流
【发布时间】:2016-10-21 21:26:58
【问题描述】:

我的 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 提供者。

【问题讨论】:

  • 尝试最新的 EclipseLink 版本,因为您的可能没有内置到惰性集合中的支持。

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


【解决方案1】:

为什么不使用real JPA Streaming

Stream<User> findAllByName(String name);

【讨论】:

  • 问这个问题的时候,JPA中没有这样的API。
【解决方案2】:

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

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

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


对我来说,最干净的解决方案是如果 IndirectList 继承自 AbstractList 并遵守 Collection API 标准,现在,在 Collection API 取代 Vector 近 20 年后(我应该提到年轻得多的 JPA实际上是?)。不幸的是,开发商没有走这条路。相反,反模式通过创建另一个类来最大化,该类继承自已经继承自非为继承而设计的类的类。此类会覆盖 Java 8 中引入的方法,并且可能会在下一个 Java 版本中获得另一个子类。

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

因此您可以推导出一些替代解决方案:

  • 关闭惰性人口
  • 继续使用 Java 7
  • 等待 JPA 2.7
  • 只需复制集合,例如
    List&lt;ElementParameter&gt; workList=new ArrayList&lt;&gt;(elementParameters);
    这个workList 将支持所有的收集和流操作

【讨论】:

  • 谢谢,我将使用第 4 种方法,将列表处理到新列表看起来最好。
猜你喜欢
  • 2016-05-20
  • 1970-01-01
  • 2015-01-18
  • 1970-01-01
  • 2012-02-10
  • 2011-04-05
  • 2020-12-28
  • 1970-01-01
  • 2012-03-01
相关资源
最近更新 更多