Primefaces lazyDataModel filter not working

373
11 января 2017, 00:39

У меня есть две таблицы stock и product. Таблицу я инициализирую через stock, но фильтр мне нужно сделать через product.

JSF:

<p:dataTable id="stockTable" value="#{stockPage.stocks}" var="stock" style="margin-top: 20px;" paginator="true" 
                         paginatorTemplate="{CurrentPageReport}  {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
                         rowsPerPageTemplate="20,100,200,500" rows="20" lazy="true" rowIndexVar = "row" emptyMessage="Ничего не найдено" reflow="true">
                <p:column headerText="Название продукта" filterBy="#{stock.product.name}">
                    #{stock.product.name}
                </p:column>

Это фильтр , но он не правильно работает:

/*
 * For Lazy
 */
public int countStock(Category category, Integer storeId, Map<String, Object> filters) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Long> cq = cb.createQuery(Long.class);
    Root<Stock> stock = cq.from(Stock.class);
    Predicate filterCondition = getFilterCondition(cb, stock, filters);
    if (category != null) {
        filterCondition = cb.and(filterCondition, cb.equal(stock.get("product").get("categoryId"), category.getId()));
    }
    filterCondition = cb.and(filterCondition, cb.equal(stock.get("storeId"), storeId));
    cq.where(filterCondition);
    cq.select(cb.count(stock));
    return em.createQuery(cq).getSingleResult().intValue();
}
// For lazy load datatable
private Predicate getFilterCondition(CriteriaBuilder cb, Root<Stock> stock, Map<String, Object> filters) {
    Predicate filterCondition = cb.conjunction();
    String wildCard = "%";
    for (Map.Entry<String, Object> filter : filters.entrySet()) {
        try {
            final String value = (String) filter.getValue();
            if (!value.equals("")) {
                Path<String> path = stock.get(filter.getKey()); // ошибка здесь!!!
                if (AbstractProduct.class.getDeclaredField(filter.getKey()).getType().equals(String.class)) {
                    String likeValue = wildCard + value + wildCard;
                    filterCondition = cb.and(filterCondition, cb.like(path, likeValue));
                } else if (AbstractProduct.class.getDeclaredField(filter.getKey()).getType().equals(Integer.class)
                        || AbstractProduct.class.getDeclaredField(filter.getKey()).getType().equals(Integer.TYPE)) {
                    try {
                        filterCondition = cb.and(filterCondition, cb.equal(path, new Integer(value)));
                    } catch (NumberFormatException e) {
                    }
                } else {
                    filterCondition = cb.and(filterCondition, cb.equal(path, filter.getValue()));
                }
            }
        } catch (NoSuchFieldException e) {
            throw new Error(e);
        } catch (ClassCastException e) {
            throw new Error(e);
        }
    }
    return filterCondition;
}

я думаю , нужно как-то через JOIN все это сделать , но точно не понимаю как , кто знает , подскажите пожалуйста.

Answer 1

Primefaces lazyDataModel filter working

В зависимости от значения ключа в фильтре есть несколько вариантов.
Один универсальный. Предполагая, что ключ равен "name":

Path<String> path;
if ("name".equals(filter.getKey()) {
   path = stock.get("product").get("name"); 
} else {
   path = stock.get(filter.getKey());
}

Если ключ равен "product.name", то можно подставить вместо "name" выше, или пойти другим путём. Для начала создать метод, получающий "вложенный" путь, потому что javax.persistence.criteria.Path.get() сам не разбирает пути.

private static Path getPath(Path p, String s) {
    for (String a : s.split("\\.")) {
        p = p.get(a);
    }
    return p;
}

Теперь применяем этот метод вместо stock.get(filter.getKey())

Path<String> path = getPath(stock, filter.getKey());

Что для "product.name" эквивалентно Path<String> path = stock.get("product").get("name");.

Я не помню какой ключ так на самом деле. Вы можете узнать это с помощью отладки, напечатать в консоль или вывести на страницу. По результатам расследования воспользоваться тем или иным вариантом.

READ ALSO
Избежать одновременного срабатывания OnDismissListener и onClick

Избежать одновременного срабатывания OnDismissListener и onClick

Этот вопрос является развитием темы Java: обойти необходимость невозможного изменения значения локальной переменной извнеИз ответов на вопрос...

257
Потеря фокуса окон в Swing

Потеря фокуса окон в Swing

Есть приложениеИнтерфейс реализован на Swing

274
Что лучше для создания игры на Android? [требует правки]

Что лучше для создания игры на Android? [требует правки]

Какую среду разработки/движок и технологии посоветуете?

223
JAXB как игнорировать поля суперкласса?

JAXB как игнорировать поля суперкласса?

Здравствуйте, уважаемые

280