Здравствуйте
Дело в том, что автоматическая генерация компонентов для DataGridEditor определяет атрибут сущности как коллекцию, поэтому для его создаётся поле для редактирования в виде MultiValuePicker
компонента, к которому добавлено два действия: MultiValueSelectAction
и ValueClearAction
.
Если обратиться к реализации этих действий, то можно увидеть, что они не передают изменения в контекст данных, а просто визуально изменяют компонент.
Я завёл задачу на то, чтобы переработать механизм генерации в случае композитной сущности: DefaultGenerationStrategy generates MultiValuePicker for entity composition attribute · Issue #3708 · jmix-framework/jmix · GitHub
Чтобы это исправить, достаточно определить другой компонент для редактирования. Это можно сделать в контроллере экрана:
@ViewComponent
private DataGrid<Order> ordersDataGrid;
@Autowired
private UiComponents uiComponents;
@Autowired
private Actions actions;
@Subscribe
public void onInit(final InitEvent event) {
ordersDataGrid.getEditor()
.setColumnEditorComponent("orderItems", context -> {
JmixMultiSelectComboBoxPicker<OrderItem> picker =
uiComponents.create(JmixMultiSelectComboBoxPicker.class);
picker.setItems(context.getItem().getOrderItems());
PickerAction lookup = actions.create(EntityLookupAction.ID);
lookup.setTarget(picker);
PickerAction clear = actions.create(MultiEntityClearAction.ID);
clear.setTarget(picker);
picker.addAction(lookup);
picker.addAction(clear);
picker.setValueSource(context.getValueSourceProvider().getValueSource("orderItems"));
return picker;
});
}
Как вы можете заметить, вместо обычного EntityClearAction
я использовал MultiEntityClearAction
. Это связано с тем, что при попытке удаления значения в компоненте с использованием EntityClearAction
происходит ошибка. Это тоже баг, на исправления которого я завёл задачу: EntityClearAction doesn't support MultiValueComboBoxPicker component · Issue #3709 · jmix-framework/jmix · GitHub
Баг связан с тем, что EntityClearAction
не поддерживает удаление коллекции. В логике действия вызывается dataContext.remove(picker.getValue())
, где в обычном случае getValue()
возвращает коллекцию сущности. А в Вашем случае picker.getValue()
вернёт коллекцию композитных сущностей.
Чтобы это решить, пришлось переписать функционал стандартного действия. Я расширил EntityClearAction
и создал в проекте свой класс MultiEntityClearAction
:
Посмотреть код
@ActionType(MultiEntityClearAction.ID)
public class MultiEntityClearAction<E> extends EntityClearAction<E> {
public static final String ID = "multi_entity_clear";
@Override
public void execute() {
ValueSource<E> valueSource = target.getValueSource();
HasValue<?, E> hasValue = (HasValue<?, E>) target;
if (!hasValue.isEmpty()
&& valueSource instanceof EntityValueSource) {
EntityValueSource<?, ?> entityValueSource = (EntityValueSource<?, ?>) valueSource;
entityValueSource.getMetaPropertyPath();
if (entityValueSource.getMetaPropertyPath().getMetaProperty().getType() == MetaProperty.Type.COMPOSITION) {
View view = UiComponentUtils.findView(((Component) target));
if (view != null) {
DataContext dataContext = ViewControllerUtils.getViewData(view).getDataContext();
if (hasValue.getValue() instanceof Collection<?> collectionValue) {
collectionValue.forEach(dataContext::remove);
} else {
dataContext.remove(hasValue.getValue());
}
}
}
}
target.setValueFromClient(getEmptyValue((Component) target));
}
}
Чтобы зарегистрировать MultiValueClearAction
Вам потребуется указать пакет для сканирования кастомных Actions в классе конфигурации приложения (главном классе SpringBoot приложения):
@Bean("my_UiActions")
public ActionsConfiguration actions(ApplicationContext applicationContext,
AnnotationScanMetadataReaderFactory metadataReaderFactory) {
ActionsConfiguration actionsConfiguration = new ActionsConfiguration(applicationContext, metadataReaderFactory);
actionsConfiguration.setBasePackages(Collections.singletonList("com.company.project.actions"));
return actionsConfiguration;
}
Надеюсь этот обходной путь Вам поможет, пока мы решаем задачи на исправления этих багов.
С уважением,
Дмитрий