我有一个像这样的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(假设我想通过索引访问这些项目)?这有些缺点吗?
答案 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);
}
}