使用延迟加载和记录计数过滤数据的最佳实践

时间:2014-02-10 07:56:30

标签: java-ee primefaces lazy-loading

我正在使用来自Primefaces的Datatable延迟加载。过滤值时,返回记录的大小小于我用于寻呼机的绝对计数。所以数据表中有空页。但我也无法使用从查询中获取的记录大小的大小,因为查询可能只返回一个子集。

实施例: 数据库中有30条记录,数据表中的页面大小为10,所以有3页,每个延迟加载请求我返回10条记录。

当我输入过滤器时,只剩下20条记录。由于绝对计数,寻呼机仍然显示3页。但是当我将记录数改为我返回的10条记录时,没有第二页。那么如何才能获得所有过滤记录的数量?有自己的查询吗?

2 个答案:

答案 0 :(得分:1)

非常多,是您自己的查询:

关于您的问题的一些讨论: Total row count for pagination using JPA Criteria API

答案 1 :(得分:1)

我使用以下策略。

首先,我创建了一个通用数据模型。这个数据模型取决于我设计我的实体(JPA),我的过滤器类和我的可分页服务的方式。请注意,我使用pojo来传输搜索条件,您需要进行一些小的更改才能使用地图过滤器参数。

以下是生成的数据模型:

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortMeta;
import org.primefaces.model.SortOrder;

public class GenericDataModel<ENTITY extends AbstractEntity, FILTER extends AbstractFilter, SERVICE extends Paginable<ENTITY, FILTER>>
        extends LazyDataModel<ENTITY> {

    private FILTER filter;

    private SERVICE service;

    private boolean started;

        //use this constructor if you want to show some result on page load
    public GenericDataModel(FILTER filter, SERVICE service) {
        this(filter, service, true);
    }

    public GenericDataModel(FILTER filter, SERVICE service, boolean autoStart) {
        this.filter = filter;
        this.service = service;
        started = autoStart;
        count();
    }

    @Override
    public List<ENTITY> load(int first, int pageSize,
            List<SortMeta> multiSortMeta, Map<String, String> filters) {

        if (!started) {
            return new ArrayList<ENTITY>();
        }

        if (getRowCount() <= 0) {
            count();
        }

        //deal with sorting here. I do that by inserting them into the filter.

        return service.find(filter);
    }

    @Override
    public List<ENTITY> load(int first, int pageSize, String sortField,
            SortOrder sortOrder, Map<String, String> filters) {

        if (!started) {
            return new ArrayList<ENTITY>();
        }

        if (getRowCount() <= 0) {
            count();
        }

        //deal with sorting here. I do that by inserting them into the filter.
        return service.find(filter);
    }

    public void count() {
        if (!started) {
            setRowCount(0);
            return;
        }

        Long rowCount = service.count(filter);
        setRowCount(rowCount == null ? 0 : rowCount.intValue());
    }

    public void start() {
        started = true;
    }
}

以下是我在托管bean上使用它的方法:

@Inject
private ProfessorService professorService;

private ProfessorFilter professorFilter;

private GenericDataModel<Professor, ProfessorFilter, ProfessorService> dataModel;

@PostConstruct
public String setup() {
    professorFilter = new ProfessorFilter();
    dataModel = new GenericDataModel(professorFilter, professorService, false);
    return null;
}

//action for the search button on the view
public void search() {
    dataModel.start();
    dataModel.count();
}

paginableService.count 方法使用select count(*)方法生成的查询所使用的相同join和where子句执行paginableService.find(filter)

对于真正庞大的数据,您可能会发现这个额外的查询可能会浪费时间和资源,但请记住,只有当您的搜索条件发生变化时才会执行此额外查询。