JPA 惰性列表上的流
stream on JPA lazy list
我的 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 提供程序。
显然,您指的是 this issue。这些惰性列表使用从实际实现(此处 Vector
)继承的反模式无法适应基础 class 的演变。请注意,根据反模式的实现方式,有两种可能的结果
- 如果延迟填充的列表在第一次使用时自行填充(继承状态),新的继承方法将在第一次访问触发器 属性 后立即开始工作
- 但是,如果列表覆盖所有访问器方法以强制委托给另一个实现,而不更新基 class 的状态,则未被覆盖的基 class' 方法将永远不会开始工作,即使列表已填充(从 subclass' 的角度来看)
显然,第二种情况适用于您。触发列表填充不会使继承的 forEach
方法起作用。请注意,通过配置关闭惰性人口可能是这里更简单的解决方案。
对我来说,最干净的解决方案是 IndirectList
继承自 AbstractList
并遵守 Collection API 标准,现在,Collection [=54= 已经快二十年了] 已经取代了 Vector
(我应该提到 JPA 实际上有多年轻吗?)。不幸的是,开发人员并没有走那条路。相反,通过创建另一个继承自 class 的 class,反模式被最大化,而 class 已经继承自并非为继承而设计的 class。此 class 覆盖 Java 8 中引入的方法,并可能在下一个 Java 版本中获得另一个子 class。
所以好消息是,开发人员期望每个 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
将支持所有 Collection 和 Stream 操作
为什么不使用 real JPA Streaming?
Stream<User> findAllByName(String name);
我的 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 提供程序。
显然,您指的是 this issue。这些惰性列表使用从实际实现(此处 Vector
)继承的反模式无法适应基础 class 的演变。请注意,根据反模式的实现方式,有两种可能的结果
- 如果延迟填充的列表在第一次使用时自行填充(继承状态),新的继承方法将在第一次访问触发器 属性 后立即开始工作
- 但是,如果列表覆盖所有访问器方法以强制委托给另一个实现,而不更新基 class 的状态,则未被覆盖的基 class' 方法将永远不会开始工作,即使列表已填充(从 subclass' 的角度来看)
显然,第二种情况适用于您。触发列表填充不会使继承的 forEach
方法起作用。请注意,通过配置关闭惰性人口可能是这里更简单的解决方案。
对我来说,最干净的解决方案是 IndirectList
继承自 AbstractList
并遵守 Collection API 标准,现在,Collection [=54= 已经快二十年了] 已经取代了 Vector
(我应该提到 JPA 实际上有多年轻吗?)。不幸的是,开发人员并没有走那条路。相反,通过创建另一个继承自 class 的 class,反模式被最大化,而 class 已经继承自并非为继承而设计的 class。此 class 覆盖 Java 8 中引入的方法,并可能在下一个 Java 版本中获得另一个子 class。
所以好消息是,开发人员期望每个 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
将支持所有 Collection 和 Stream 操作
为什么不使用 real JPA Streaming?
Stream<User> findAllByName(String name);