如何将来自一个实体的ComboBox值绑定到另一个实体
Vaadin中ComboBox绑定关联实体ID的解决方案
问题场景
我尝试将Car实体的数据与关联的Brand实体进行绑定,实体定义如下:
Car实体
public class Car { @Id private Long carId; private String carName; private Long brandId; // 其他字段及 getter/setter }
Brand实体
public class Brand { @Id private Long brandId; private String brandName; // 其他字段及 getter/setter }
在视图类CarDetailView中,我使用ComboBox展示品牌名称,但绑定器binder是针对Car实体配置的:
public class CarDetailView extends Div implements BeforeEnterObserver { private ComboBox<String> brandNames; private BeanValidationBinder<Car> binder; private void createBasicLayout(SplitLayout splitLayout) { brandNames = new ComboBox<>("Brand name"); brandNames.setItems(brandRepository.findAllBrandNames()); // 返回数据库中所有品牌名称(如Volkswagen、Volvo、Audi等) } }
ComboBox能正常显示所有品牌名称,但选择值后无法绑定到Car实体——核心问题是需要从ComboBox选中的文本中获取对应的brandId,再通过binder设置到Car实体里。
尝试过的方法及报错
我曾尝试使用Pair来存储brandId和brandName:
private ComboBox<Pair<Long, String>> brandNames;
但绑定依然失败,抛出异常:
Caused by: java.lang.IllegalStateException: Property type 'java.lang.Long' doesn't match the field type 'com.vaadin.flow.internal.Pair<java.lang.Long, java.lang.String>'. Binding should be configured manually using converter.
可行解决方案
采用Simon Martinelli的方案,直接将ComboBox的类型设置为Brand实体,通过转换器实现Brand与Long(brandId)之间的双向转换:
public class CarDetailView extends Div implements BeforeEnterObserver { private ComboBox<Brand> brand; private BeanValidationBinder<Car> binder; private void createBasicLayout(SplitLayout splitLayout) { binder = new BeanValidationBinder<>(Car.class); binder.bindInstanceFields(this); brand = new ComboBox<>("Brand name"); brand.setItems(brandRepository.findAllBrands()); // 返回所有Brand实体 // 构建brandId与Brand实体的映射,实际可从数据库查询结果初始化 Map<Long, Brand> brandMap = new HashMap<>() {{ put(2000000L, new Brand(2000000L, "Audi")); put(2000001L, new Brand(2000001L, "Volvo")); }}; // 为ComboBox绑定转换器,实现Brand与brandId的双向转换 binder.forField(brand) .withConverter(new Converter<Brand, Long>() { @Override public Result<Long> convertToModel(Brand value, ValueContext context) { return Result.ok(value == null ? null : value.getBrandId()); } @Override public Brand convertToPresentation(Long value, ValueContext context) { return brandMap.get(value); } }).bind(Car::getBrandId, Car::setBrandId); // 设置ComboBox显示品牌名称 brand.setItemLabelGenerator(brand -> brand.getBrandName()); } }
内容的提问来源于stack exchange,提问作者Andromeda
相关产品推荐
相关产品推荐

