У меня есть две таблицы 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 все это сделать , но точно не понимаю как , кто знает , подскажите пожалуйста.
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");
.
Я не помню какой ключ так на самом деле. Вы можете узнать это с помощью отладки, напечатать в консоль или вывести на страницу. По результатам расследования воспользоваться тем или иным вариантом.
Этот вопрос является развитием темы Java: обойти необходимость невозможного изменения значения локальной переменной извнеИз ответов на вопрос...
Какую среду разработки/движок и технологии посоветуете?