【问题标题】:Ordered collection with Hibernate使用 Hibernate 的有序集合
【发布时间】:2017-04-06 12:35:56
【问题描述】:

我有一个这样的容器类:

@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 实现了一些其他处理项目的方法,此处未显示) .在此之后,我需要一个按时间戳排序的项目,如下所示:

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

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

【问题讨论】:

  • 为什么不在返回有序集的方法中正确排序?如果您在此集合中没有超过 1000 个对象 - 将不会出现性能问题。
  • 通常这个集合有大约 1000 到 100k 个项目,但可能需要扩展到 10^6 个元素......而且似乎它将来需要某种分页......
  • 好吧,您可以尝试从外部获取一组项目,而不使用 ORM 映射或延迟加载,然后附加到这个“容器”实体。在这种情况下将是一种实现分页的方法。

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


【解决方案1】:

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

所以,首先,我并不完全清楚为什么不建议在构造函数或设置器中初始化集合,但在显示的情况下似乎没问题。其次,如果 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);
     }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    • 1970-01-01
    • 2013-11-21
    相关资源
    最近更新 更多