使用Hibernate订购集合

时间:2017-04-06 12:35:57

标签: java hibernate collections orm sql-order-by

我有一个像这样的Container类:

@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);
     }
}

可以看出,Container是一个对象关系映射,包含一组项目,并向客户端公开项目的不可修改的ObservableSet(另外,Container实现了一些其他方法来处理Items,这里没有显示) 。在此之后,我需要按时间戳排序的项目,像这样:

 @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作为背景设置?在构造函数中设置所需的类是否足够?

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

或者可能只是用一个List替换一个Set(假设我想通过索引访问这些项目)?这有些缺点吗?

1 个答案:

答案 0 :(得分:0)

从Bauer,Java Persistence with Hibernate,第二版,第143页,我引用“我们不建议在构造函数或setter方法中延迟初始化集合”。进一步“ Hibernate包装了你已经在声明的声明中初始化的集合,或者有时替换它,如果它不是正确的”。在本书中也说过,如果你需要一个具有稳定的交互顺序的集合,你可以使用LinkedHashSet。但是从PersistentSet的javadoc(一个Set的持久包装器)我看到,“底层集合是一个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);
     }
}