集合容器
CollectionContainer
接口用来容纳相同类型实例的集合。这个接口继承自 InstanceContainer
。
在 XML 描述中可以这样定义 CollectionContainer
:
<collection id="departmentsDc"
class="com.company.onboarding.entity.Department">
<fetchPlan extends="_base">
<property name="hrManager" fetchPlan="_base"/>
</fetchPlan>
<loader id="departmentsDl" readOnly="true">
<query>
<![CDATA[select e from Department e]]>
</query>
</loader>
</collection>
方法
CollectionContainer
定义了下列特殊方法:
-
setItems()
- 为容器设置实体集合。 -
getItems()
- 返回容器中保存的实体的不可变列表。可以用这个方法来遍历集合、获取 stream 或者根据实体位置获取单一实例。如果需要按照实体的 id 获取实例,使用getItem(entityId)
方法。示例:@ViewComponent private CollectionContainer<Department> departmentsDc; private Optional<Department> findByName(String name) { return departmentsDc.getItems().stream() .filter(department -> Objects.equals(department.getName(), name)) .findFirst(); }
-
getMutableItems()
- 返回容器中保存的实体的可变列表。所有对列表的改动,包括add()
、addAll()
、remove()
、removeAll()
、set()
、clear()
方法都会产生CollectionChangeEvent
事件,所以订阅了这个事件的可视化组件也会根据变化更新,示例:@ViewComponent private CollectionContainer<Department> departmentsDc; private void createDepartment() { Department department = metadata.create(Department.class); department.setName("Operations"); departmentsDc.getMutableItems().add(department); }
只有在需要更改集合的时候使用 getMutableItems()
,否则应该使用getItems()
,防止意外改动。 -
setItem()
- 为容器设置当前实例。如果提供的内容不是null
,则必须是集合中的一个对象。此方法会发送ItemChangeEvent
。需要注意的是,类似 DataGrid 的可视化组件不会监听容器发送的
ItemChangeEvent
事件。所以如果需要在DataGrid
中选中一行,需要使用DataGrid
的setSelected()
方法,而不是容器的setItem()
。同时,容器的当前 item 也会更改,因为容器也监听了组件变化。示例:@ViewComponent private DataGrid<Department> departmentsTable; @ViewComponent private CollectionContainer<Department> departmentsDc; private void selectFirstRow() { departmentsTable.getSelectionModel() .select(departmentsDc.getItems().get(0)); }
-
getItem()
- 重写了InstanceContainer
的同名方法,返回当前实例。如果当前实例没有设置,此方法会抛出一个异常。所以需要在确保容器有选中当前实例的时候才使用此方法,然后就不需要检查返回值是否为null
。 -
getItemOrNull()
- 重写了InstanceContainer
的同名方法,返回当前实例。如果当前实例没有设置,此方法会返回null
。所以在使用此方法返回值之前总是需要先检查返回的是否是null
。 -
getItemIndex(entityId)
- 返回实例在getItems()
和getMutableItems()
方法返回的列表中的位置。此方法接收Object
对象,因此可以传给它 id 或者实体实例本身。容器的实现维护了一个 id 到索引的映射,所以这个方法即使在非常大的列表中也有很高效率。 -
getItem(entityId)
- 根据实例的 id 返回此实例。这个是一个快捷方法,首先用getItemIndex(entityId)
得到实例的位置,然后通过getItems().get(index)
返回实例。所以如果需要找的实例不在集合中存在,则会抛出异常。 -
getItemOrNull(entityId)
- 与getItem(entityId)
类似,只不过在实例不存在的时候会返回null
。所以需要在使用前检查此方法的返回值是否是null
。 -
containsItem(entityId)
- 如果指定 id 的实体在集合中存在的话,返回 true。底层其实调用了getItemIndex(entityId)
方法。 -
replaceItem(entity)
- 如果在容器中有相同 id 的实例,则会被方法的输入参数的实例替换。如果不存在,则会添加新的实例到实例列表中。此方法会发送CollectionChangeEvent
事件,根据具体的操作,事件类型可以是SET_ITEM
或者ADD_ITEMS
。 -
setSorter()
- 设置此容器的排序器。Sorter
接口的标准实现是CollectionContainerSorter
。当容器关联到加载器时,会设置默认的排序器。如果需要,也可提供 自定义实现。 -
getSorter()
- 返回此容器当前设置的排序器。
事件
除了 InstanceContainer 的事件之外,还可以使用 CollectionContainer
接口的 CollectionChangeEvent
事件的监听器,该事件在容器内的实体集合改动时发送,比如,添加、删除和替换集合内元素。下面示例中订阅了该事件,容器在界面 XML 中使用 id departmentsDc
定义:
@Subscribe(id = "departmentsDc", target = Target.DATA_CONTAINER)
public void onDepartmentsDcCollectionChange(
final CollectionContainer.CollectionChangeEvent<Department> event) {
CollectionChangeType changeType = event.getChangeType(); (1)
Collection<? extends Department> changes = event.getChanges(); (2)
// ...
}
1 | 获取改动类型:REFRESH 、ADD_ITEMS 、REMOVE_ITEMS 、SET_ITEM 。 |
2 | 从容器中添加或者删除的实体集合。如果改动类型是 REFRESH ,框架不能确定具体是哪些实体添加或者删除,所以此时该集合为空。 |