使用 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);
}
}
我有一些这样的容器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);
}
}