How to persist checkBoxGroup as java.util.Collection to Postgres?

I have an Enum with options. User can select one or more options in the checkbox.
Is there a way to persist whole CheckBocGroup in one property/column?
E.g. Postgres has an array type…
Or do I have to make column for all checkbox option separately?
Thank you!
Tomas

Hi,

The easiest solution may be to store a list as a string with comma separated values. When you need to display it in UI, convert this string to a collection of enums and set the collection to the UI component. When you need to save it, convert a Collection<MyEnum> into a string with comma-separated enum ids.

Also, you may define a JPA AttributeConverter, similar to the one, described in this topic. Your converter will convert a List<MyEnum> into a String. In this case your entity will have a field of List<MyEnum> type, and a conversion to a string with comma-separated values will be done inside the converter.

OK, thank you. I think I got it.

But anyway… The framework provides several “multi” components. The CheckBoxGroup is not the only one…

You only show how to load the options/listItems everywhere. BUT no solution, no example how to store/persist the selected items.

That could be improved I geuss… At least the demo, example, documentation… And ideal solution is to build it into the Studio.

Thank you.

1.5

MultiSelectList

CheckBoxGroup

2.0

multiSelectComboBox

multiSelectListBox

multiValuePicker

https://docs.jmix.io/jmix/flow-ui/vc/components/multiValuePicker.html

https://docs.jmix.io/jmix/flow-ui/vc/components/multiSelectListBox.html

https://docs.jmix.io/jmix/1.5/ui/vcl/components/multi-select-list.html

https://demo.jmix.io/ui-samples/sample/checkbox-group-dataaware

Hi Maxim, thank you, I made it work.

BUT guess what happened in Designer? In is not supported by your Designer.
Try it, switch to Entity designer and back to Text source code. List is removed. This type is not supported.

So all the changes in the source code are deleted!

That is sad. And it is a bug.
Create a ticket for that please.

And consider rethinking the support for multi elements like checkboxes, mlutiSelecr and multivalue… It doesnt work in the framework at all…

@gorbunkov Thanks.

I’ve created an issue for Studio.Thanks for reporting.

And consider rethinking the support for multi elements like checkboxes, mlutiSelecr and multivalue… It doesnt work in the framework at all…

Could you please explain in more details what do you mean by “it doesn’t work at all”. If possible, please provide some examples what do you expect, what you do and what doesn’t work.

OK, I will try to explain it…

The framework offers:
v1.5

  • MultiSelectList
  • CheckBoxGroup

v2.0

  • multiSelectComboBox
  • multiSelectListBox
  • multiValuePicker

But it is not possible to use it with database.
It is not possible to save the values.
All your examples and documentation only shows how to load options.
But how to bind it to a property to save selected items and to reload them from db next time… No example, nothing. At least I did not find.

Could you make a simple example app, which will persist Checkboxgroup? It will be clear immediately.
Thank you.

Hi Tomas

Looks like you managed to store value from EntityComboBox ?

In a Browse-View i did insert a generated column with an EntityComboBox which i populate and set the selected item from the database. This is working as expected.

Then in the DcItemChange i want to store the selected value in the database

	@Autowired
	private DataContext dataContext;

	@Autowired
	private UiComponents uiComponents;

	@Autowired
	private Metadata metadata;

	private EntityComboBox<OrderState> picker = null;

	@Subscribe(id = "ordersesDc", target = Target.DATA_CONTAINER)
	public void onOrdersesDcItemChange(InstanceContainer.ItemChangeEvent<Orders> event)
	{
		ArrayList<OrderState> selectedState = new ArrayList<>(picker.getLookupSelectedItems());
		System.out.println("selected = " + selectedState.size() + ") " + selectedState.get(0).getState() + " " + selectedState.get(0).getDescription() );
		dataContext.commit();
	}

	@Autowired
	protected CollectionContainer<OrderState> orderStatesDc;

	@Install(to = "ordersesTable.orderState", subject = "columnGenerator")
	private Component ordersesTableOrderStateColumnGenerator(final Orders orders)
	{
		picker = uiComponents.create(EntityComboBox.class);
		picker.setMetaClass(metadata.getClass(OrderState.class));
		picker.setOptionsContainer(orderStatesDc);
		picker.setValue(orders.getOrderState());
		picker.setWidth("100px");
		return picker;
	}

In onOrdersesDcItemChange i should get the SelectedItem. But it is everytime the last item in the picker list.

What am I doing wrong ?

My solutions:

I have this real-world form:
image

I represent it as CheckBoxGroup.
Then the data are stored a CSV using a convertor.


@Column(name = "MEANS_OF_SUPPORT_APPLICANTS")
@Convert(converter = MosSelfConverter.class)
private Collection<CostOfTravellingAndLivingSelf> meansOfSupportApplicants;

And the convertor is:

@Converter
public class MosSelfConverter implements AttributeConverter<Collection<CostOfTravellingAndLivingSelf>, String> {

    private static final Logger log = LoggerFactory.getLogger(MosSelfConverter.class);

    @Override
    public String convertToDatabaseColumn(Collection<CostOfTravellingAndLivingSelf> attribute) {
        return StringUtils.join(attribute,",");
    }

    @Override
    public Collection<CostOfTravellingAndLivingSelf> convertToEntityAttribute(String dbData) {
        Collection<CostOfTravellingAndLivingSelf> col = new ArrayList<CostOfTravellingAndLivingSelf>();
        if (dbData == null) {
            return col;
        }
        try {
            List<String> list = new ArrayList<String>(Arrays.asList(dbData.split(",")));
            CostOfTravellingAndLivingSelf cost;
            for (String s : list) {
                cost = null;
                try {
                    cost = CostOfTravellingAndLivingSelf.valueOf(s);
                } catch (IllegalArgumentException e) {
                    log.error(e.getMessage());
                }
                if (cost != null) {
                    col.add(cost);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return col;
    }
}

The OptionsContainer is an Enum:

public enum CostOfTravellingAndLivingSelf implements EnumClass<String> {

    CASH("Cash"),
    TRAVELLERS_CHEQUES("Traveller's cheques"),
    CREDIT_CARD("Credit card"),
    PREPAID_ACCOMMODATION("Pre-paid accommodation"),
    PREPAID_TRANSPORT("Pre-paid transport "),
    OTHER("Other");

    private String id;

    CostOfTravellingAndLivingSelf(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    @Nullable
    public static CostOfTravellingAndLivingSelf fromId(String id) {
        for (CostOfTravellingAndLivingSelf at : CostOfTravellingAndLivingSelf.values()) {
            if (at.getId().equals(id)) {
                return at;
            }
        }
        return null;
    }
}

I dont display it in a View. But in a Form it works just fine.

In my case I dant care musch about selected values. So I am fine with a CSV column. My ideal solution would be to use PostgreSQL text[] array column. But it is not supported.

In my another usecase I have PurposeOfJourney. In this case I dont use CheckboxGroup but individual Checkboxes each having a boolean column in the database.

Hope it helps…