问题 初始化或不初始化JPA关系映射?


在一对多的JPA协会中,它被认为是初始化与空集合的关系的最佳实践?例如。

@Entity
public class Order { 

   @Id
   private Integer id;

   // should the line items be initialized with an empty array list or not?
   @OneToMany(mappedBy="order")
   List<LineItem> lineItems = new ArrayList<>();

}

在上面的例子中,定义更好 lineItems 默认值为空 ArrayList 或不?优缺点都有什么?


12623
2017-12-21 03:39


起源



答案:


JPA本身并不关心集合是否已初始化。使用JPA从数据库中检索订单时,JPA会 总是 返回带有非空OrderLines列表的Order。

原因:因为订单可以包含0行,1行或N行,并且最好使用空的,一个大小或N个大小的集合建模。如果集合为null,则必须在代码中的任何位置检查它。例如,如果列表为null,则此简单循环将导致NullPointerException:

for (OrderLine line : order.getLines()) {
    ...
}

因此,最好通过始终具有非空集合使其成为不变量,即使对于新创建的实体实例也是如此。这使得生产代码创建新订单更安全,更清洁。这也使得您的单元测试使用不是来自数据库的Order实例,更安全,更清洁。


15
2017-12-21 06:51



我想知道如果你声明一个字段会发生什么 final 然后使用lazy fetch - basin


答案:


JPA本身并不关心集合是否已初始化。使用JPA从数据库中检索订单时,JPA会 总是 返回带有非空OrderLines列表的Order。

原因:因为订单可以包含0行,1行或N行,并且最好使用空的,一个大小或N个大小的集合建模。如果集合为null,则必须在代码中的任何位置检查它。例如,如果列表为null,则此简单循环将导致NullPointerException:

for (OrderLine line : order.getLines()) {
    ...
}

因此,最好通过始终具有非空集合使其成为不变量,即使对于新创建的实体实例也是如此。这使得生产代码创建新订单更安全,更清洁。这也使得您的单元测试使用不是来自数据库的Order实例,更安全,更清洁。


15
2017-12-21 06:51



我想知道如果你声明一个字段会发生什么 final 然后使用lazy fetch - basin


我还建议使用Guava的不可变集合,例如,

import com.google.common.collect.ImmutableList;
// ...
@OneToMany(mappedBy="order")
List<LineItem> lineItems = ImmutableList.of();

这个成语从不创建一个新的空列表,但重用一个表示空列表的实例(类型无关紧要)。这是函数式编程语言的一种非常常见的做法(Scala也这样做)并减少到  拥有空对象而不是空值的开销,使得对成语的任何效率论证都没有实际意义。


1
2018-02-27 17:53



但是,对于JPA实体,我认为你应该用a初始化 易变的 列表,将该字段设为私有,仅为您的集合提供公共getter。只有这样,你才能确定 lineItems 永远不会 null。我不担心创建空列表,因为现代JVM非常适合垃圾收集。一般说明:永远不要预先优化您的代码! - Stefan Haberl
我同意@StefanHaberl,你不应该用不可变集合初始化实体字段。这将使创建实体和测试的新实例变得困难。如果你担心性能,你可能会尝试类似的东西 new HashSet<>(0) (stackoverflow.com/questions/18076492/...)。 - csharpfolk