集合实例容器
CollectionContainer
接口用来容纳相同类型实例的集合。这个接口继承自 InstanceContainer
。
在 XML 描述中可以这样定义 CollectionContainer
:
<data readOnly="true">
<collection id="customersDc"
class="ui.ex1.entity.Customer">
<fetchPlan extends="_base"/>
<loader id="customersDl" >
<query>
<![CDATA[select e from uiex1_Customer e]]>
</query>
</loader>
</collection>
</data>
方法
CollectionContainer
定义了下列特殊方法:
-
setItems()
- 为容器设置实体集合。 -
getItems()
- 返回容器中保存的实体的不可变列表。可以用这个方法来遍历集合、获得实体流或者根据索引获取单一实例。如果需要按照实体的 id 获取实例,使用getItem(entityId)
方法。示例:@Autowired private CollectionContainer<Customer> customersDc; private Optional<Customer> findByName(String name) { return customersDc.getItems().stream() .filter(customer -> Objects.equals(customer.getLastName(), name)) .findFirst(); }
-
getMutableItems()
- 返回容器中保存的实体的可变列表。所有对列表的改动,包括add()
、addAll()
、remove()
、removeAll()
、set()
、clear()
方法都会产生CollectionChangeEvent
事件,所以订阅了这个事件的可视化组件也会根据变化更新,示例:@Autowired private CollectionContainer<Customer> customersDc; private void createCustomer() { Customer customer = metadata.create(Customer.class); customer.setFirstName("John"); customer.setLastName("Doe"); customersDc.getMutableItems().add(customer); }
只有在需要更改集合的时候使用 getMutableItems()
,否则应该使用getItems()
,防止意外改动。 -
setItem()
- 为容器设置当前实例。如果提供的内容不是null
,则必须是集合中的一个对象。此方法会发送ItemChangeEvent
。需要注意的是,类似
Table
的可视化组件不会监听容器发送的ItemChangeEvent
事件。所以如果需要在表中选中一行,需要使用集合容器的setSelected()
方法,而不是setItem()
。容器的当前 item 也会更改,因为容器同时也监听了组件。示例:@Autowired private CollectionContainer<Customer> customersDc; @Autowired private GroupTable<Customer> customersTable; private void selectFirstRow() { customersTable.setSelected(customersDc.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 customersDc
定义:
@Subscribe(id = "customersDc", target = Target.DATA_CONTAINER)
public void onCustomersDcCollectionChange(CollectionContainer.CollectionChangeEvent<Customer> event) {
CollectionChangeType changeType = event.getChangeType(); (1)
Collection<? extends Customer> changes = event.getChanges(); (2)
// ...
}
1 | 获取改动类型:REFRESH 、ADD_ITEMS 、REMOVE_ITEMS 、SET_ITEM 。 |
2 | 从容器中添加或者删除的实体集合。如果改动类型是 REFRESH ,框架不能确定具体是哪些实体添加或者删除,所以此时该集合为空。 |