使用 Hibernate 有序集合

Ordered collection with Hibernate

我有一些这样的容器class:

@Entity
class Container {
     private Set<Item> itemsInternal;
     private ObservableSet<Item> items;
     private ObservableSet<Item> roItems;

     // ORM access by PROPERTY

     public Container() {
         setItemsInternal(new HashSet<>());
     }

     @Transient
     public ObservableSet<Item> getItems() {return roItems;}

     // private methods for ORM   

     @OneToMany(mappendBy = "parent")
     private Set<Item> getItemsInternal() {
          return itemsInternal;
     }

     private void setItemsInternal(Set<Item> value) {
         itemsInternal = value;
         items = FXCollection.observableSet(itemsInternal);
         roItems = FXCollection.unmodifiableObservableSet(items);
     }
}

正如所见,容器是一个对象关系映射,包含项目集并向客户端公开项目的不可修改的 ObservableSet(此外,容器实现了一些其他方法来处理项目,未显示这里)。在此之后我需要一个按时间戳排序的项目,像这样:

 @OneToMany(mappedBy = "parent")
 @OrderBy("created")
 Set<Item> items = new LinkedHashSet<Item>();

但在我之前显示的当前实现中,ORM 通过 setter:

设置 Set
 private void setItemsInternal(Set<Item> value) {
     itemsInternal = value;
     items = FXCollection.observableSet(itemsInternal);
     roItems = FXCollection.unmodifiableObservableSet(items);
 }

而且我不可能使用 LinkedHashSet 作为背景集。

这种情况下如何使用LinkedHashSet作为背景集?在构造函数中设置所需的 class 就足够了吗?

 public Container() {
         setItemsInternal(new LinkedHashSet<>());
 }

或者只是用列表替换集合(假设我想通过索引访问项目)?这里有什么缺点吗?

来自 Bauer,Java Hibernate 的持久性,第二版,第 143 页,我引用“我们不建议在构造函数或 setter 中延迟初始化集合方法”。并且进一步“Hibernate 包装你已经在声明文件时初始化的集合,或者有时替换它,如果它不是正确的”。另外在这本书中说,如果你需要一个具有稳定交互顺序的集合,你可以使用 LinkedHashSet。但是从 PersistentSet 的 javadoc(集合的持久包装器)我看到,“底层集合是一个 HashSet。

所以,首先,我不完全清楚为什么不建议在构造函数或 setter 中初始化集合,但在所示情况下似乎没问题。其次,如果 Set 由 @OrderBy 标记,则在检索实体时,Hibernate 使用 LinkedHashSet 作为基础集合而不是 HashSet。因此,要获得稳定的迭代顺序,只需使用注释 @OrderBy 标记 Set 并使用 LinkedHashSet 进行首次初始化。

@Entity
class Container {
     private Set<Item> itemsInternal;
     private ObservableSet<Item> items;
     private ObservableSet<Item> roItems;

     // ORM access by PROPERTY

     public Container() {
        // first time collection initialization 
         setItemsInternal(new LinkedHashSet<>());
     }

     @Transient
     public ObservableSet<Item> getItems() {return roItems;}

     // private methods for ORM   

     @OneToMany(mappendBy = "parent")
     // order the data when querying the DB 
     // and use LinkedHashSet as underlying collection
     @OrderBy("created") 
     private Set<Item> getItemsInternal() {
          return itemsInternal;
     }

     private void setItemsInternal(Set<Item> value) {
         itemsInternal = value;
         items = FXCollection.observableSet(itemsInternal);
         roItems = FXCollection.unmodifiableObservableSet(items);
     }
}