是否可以将AbstractBackEndDataProvider转换为ListProvider?

时间:2019-08-11 07:24:08

标签: java vaadin

我已经基于此处的链接编写了一个自定义的https://mindbug.in/vaadin/vaadin-dataprovider-example/ CallBackDataProvider,用于多选组合框(Vaadin的插件目录中的插件https://github.com/bonprix/vaadin-combobox-multiselect),目的是提供延迟加载项。

根据插件的clear()和selectAll(),它需要一个ListDataProvider。我已经将组件的数据提供程序设置为使用上面的自定义数据提供程序。每当触发clear或selectAll函数时,都会引发Class Cast Exception。它期待一个ListDataProvider。

这种情况下最直接的解决方法是通过将boolean标志设置为false来禁用clear和selectAll方法,但是从用户的角度来看,这并不灵活。

尝试进行的另一步骤是将流转换为“收藏夹列表”,但是没有用。它仍然会引发错误。

这是自AbstractBackendDataProvider扩展的自定义CallbackDataProvider:

    public ItemDataProvider(ReceiptService receiptService) {
        if(receiptService != null){
            this.receiptService = receiptService;
        }else {
            this.receiptService = new ReceiptService();
        }
    }

    @Override
    protected Stream<SkusSelectBox> fetchFromBackEnd(Query<SkusSelectBox, String> query) {
        stream = receiptService.fetchSkus(query.getFilter().orElse(null), query.getLimit(), query.getOffset(), query.getSortOrders()).stream();
        return stream;
    }

    @Override
    protected int sizeInBackEnd(Query<SkusSelectBox, String> query) {
        return receiptService.countSkus(query.getFilter().orElse(null));
    }

    @Override
    public Object getId(SkusSelectBox item) {
        return item.getItemId();
    }

    public Stream<SkusSelectBox> getStream(){
        return stream;
    }

SkuSelectBox是一个简单的两个字符串属性对象,用于检索id和名称。

对于此组件,我已在视图页面上设置了以下内容:

ItemDataProvider itemDataProvider = new ItemDataProvider(receiptService);

        ComboBoxMultiselect<SkusSelectBox> skuSelect = new ComboBoxMultiselect<>("Items");
        skuSelect.setPlaceholder("Choose Items");
        skuSBox.add(new SkusSelectBox("0", "No data found"));
        skuSelect.setWidth(80, Unit.PERCENTAGE);
        skuSelect.setRequiredIndicatorVisible(true);
        skuSelect.setItemCaptionGenerator(SkusSelectBox::getItemName);
        skuSelect.setSelectAllButtonCaption("Select All");
        skuSelect.setClearButtonCaption("Clear");
        skuSelect.showSelectAllButton(true); 
        skuSelect.showClearButton(true);
        skuSelect.setDataProvider(itemDataProvider);
        skuSelect.getDataProvider().refreshAll();
        skuSelect.isReadOnly();
        skuSelect.setPageLength(20);
        if(skuSBox.size() <=1 ){
           skuSelect.showSelectAllButton(false);
           //skuSelect.showClearButton(false);
        } 

        skuSelect.setResponsive(true);

selectAll和clear方法非常相似,除了方法的最后:

@Override
        public void selectAll(final String filter) {
            final ListDataProvider<T> listDataProvider = ((ListDataProvider) getDataProvider());
            final Set<String> addedItems = listDataProvider.getItems()
                    .stream()
                    .filter(t -> {
                        final String caption = getItemCaptionGenerator().apply(t);
                        if (t == null) {
                            return false;
                        }
                        return caption.toLowerCase()
                                .contains(filter.toLowerCase());
                    })
                    .map(t -> itemToKey(t))
                    .collect(Collectors.toSet());
            updateSelection(addedItems, new HashSet<>(), true);
            updateSelection(new HashSet<>(), removedItems, true); (this is for clear method)
        }

基本上,该错误消息中显示了类强制转换异常,它引用了我调用的方法clear或selectAll:

java.lang.ClassCastException: com.igi.sycarda.dashboard.hib.utils.ItemDataProvider cannot be cast to com.vaadin.data.provider.ListDataProvider
    at org.vaadin.addons.ComboBoxMultiselect$1.clear(ComboBoxMultiselect.java:224)

我正在查看selectAll或clear方法,该方法被调用来像平常一样工作,就像不使用CallbackDataProvider一样。

在该插件的下一个补丁程序发布之前,我需要解决此问题,如何才能将自定义提供程序转换为ListDataProvider的快速变脏方式或更清洁的方式(如果需要)?

更新:通常,我将从服务类中直接获取数据,但是当与拥有约20K项记录的租户进行测试时,页面和特定组件框的加载是加载速度很慢。该CallbackDataProvider将测试它是否适用于大量记录。

2 个答案:

答案 0 :(得分:0)

使用列表数据提供程序的想法是将所有项目都加载到内存中。可以将所有项目从数据库加载到内存中,然后使用它来创建列表数据提供程序。另一方面,这确实使建立回调数据提供程序的目的无法实现。

直接从receiptService而不是通过现有的数据提供程序将项目提取到列表中,可能会更直接。

答案 1 :(得分:0)

由于存在限制或导致我执行错误的方法,所以有人建议我创建一个从所需表/列派生的视图,并使用它们代替普通表。

创建视图后,我将以下几行还原并删除为常规实现:

skuSelect.setDataProvider(itemDataProvider);
        skuSelect.getDataProvider().refreshAll();
        skuSelect.isReadOnly();
        skuSelect.setPageLength(20);
        if(skuSBox.size() <=1 ){
           skuSelect.showSelectAllButton(false);
           //skuSelect.showClearButton(false);
        } 

在撰写本文时,我们已经在一小时前对其进行了测试,并且在不牺牲性能时间和创建其他组件的情况下解决了该问题。在时间测量方面,视图中的20K结果集在不到10秒的时间内加载,而之前是7-9分钟。