Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Создайте универсальный метод, использующий JPA2 и CriteriaBuilder.

Автор вопроса: Filippo1980Ответов: 2

Я разрабатываю веб-приложение, использующее фреймворки JSF2 и JPA2. Я начал использовать мастера в netbeans7.0, и "Новые страницы JSF из классов сущностей", созданные classAbstractFacade, содержат этот полезный метод:

public List<T> findRange(int[] range) {
  javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
  cq.select(cq.from(entityClass));
  javax.persistence.Query q = getEntityManager().createQuery(cq);
  q.setMaxResults(range[1] - range[0]);
  q.setFirstResult(range[0]);
  return q.getResultList();
}

где T - это класс сущности, который содержит структуру базы данных таблицы, а переменная диапазона содержит два числа для получения подсписка результатов! Теперь я изменяю его, чтобы установить порядок по предложению и проверить, является ли пользователь диапазоном или нет, и новый код:

    public List<T> findRangeOrdered(int[] range, String orderBy) {
      javax.persistence.criteria.CriteriaQuery<T> cq = (javax.persistence.criteria.CriteriaQuery<T>)getEntityManager().getCriteriaBuilder().createQuery();
      cq.select(cq.from(entityClass));
      javax.persistence.criteria.Root<T> r = cq.from(entityClass);
      if(orderBy!=null && !orderBy.equals("")){
        if(orderBy.ebdsWith(" desc"))
          cq.orderBy(getEntityManager().getCriteriaBuilder().desc(r.get(orderBy.substring(0,orderBy.indexOf(" ")))));
        else
          cq.orderBy(getEntityManager().getCriteriaBuilder().desc(r.get(orderBy.substring(0,orderBy.indexOf(" ")))));
      }
      javax.persistence.Query q = getEntityManager().createQuery(cq);
      if(range!=null)
      {
        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
      }
      return q.getResultList();
    }

Теперь я бы добавил несколько вариантов. Я думаю о добавлении переменной List, которая может содержать HashMap с этой парой значений key-->:

  • "тип" --> тип поля, которое я бы искал (например, String.class или java.util.Date.class);
  • "имя" --> имя поля в классе сущностей;
  • "value0" --> первое значение, которое я ищу;
  • "value1" --> второе значение для предложения "between";
  • "предложение" --> какой фильтр я хочу использовать.

Теперь у меня есть некоторые сомнения:

1) это хорошая идея?

2) сделать выход из фреймворка, который уже реализует эту функцию?

3) если ответы на предыдущие вопросы: Да, это хорошая идея; и Нет, нет никакой структуры, которая уже делает это, я нахожу эти новые проблемы: этот новый метод возвращает мне некоторые ошибки компилятора:

public List<T> findAllFiltered(int[] range, String orderBy, List<HashMap<String,Object>> whereList) {
  List<Predicate> predicateList = new ArrayList<Predicate>();
  String buf;
  HashMap<String,Object> where;
  int i=0;
  javax.persistence.criteria.CriteriaQuery<T> cq = (javax.persistence.criteria.CriteriaQuery<T>)getEntityManager().getCriteriaBuilder().createQuery();
  cq.select(cq.from(entityClass));
  javax.persistence.criteria.Root<T> r = cq.from(entityClass);
  javax.persistence.criteria.Path<T> path = cq.from(entityClass);
  if(whereList!= null && whereList.size()>0){
    Iterator iter=whereList.iterator();
    Predicate p;
    while (iter.hasNext())
    {
      where=(HashMap<String,Object>)iter.next();

      if(where.get("where").toString().equals("like"))
        p = getEntityManager().getCriteriaBuilder().like(getEntityManager().getCriteriaBuilder().upper(r.<String>get(where.get("name").toString())), "%"+where.get("value0").toString().toUpperCase()+"%");
      else if(where.get("where").toString().equals("equal"))
        p = getEntityManager().getCriteriaBuilder().equal(r.get(where.get("name").toString()), where.get("value0").toString());
      else if(where.get("where").toString().equals("in"))
        p = getEntityManager().getCriteriaBuilder().and(r.get(where.get("name").toString()).in(where.get("value0").toString().replaceAll("#",",")));
      else if(where.get("where").toString().equals("between"))
      {
        java.util.Date value0=(java.util.Date)where.get("value0");
        java.util.Date value1=(java.util.Date)where.get("value1");
        p = getEntityManager().getCriteriaBuilder().between(r.<java.util.Date>get(where.get("name").toString()),value0,value1);
      }
      else if(where.get("where").toString().equals("greatest"))
        p = getEntityManager().getCriteriaBuilder().and(getEntityManager().getCriteriaBuilder().greatest(r.<Long>get(where.get("name").toString())));
      else if(where.get("where").toString().equals("greaterThanOrEqualTo"))
      {
        java.util.Date value0=(java.util.Date)where.get("value0");
        p = getEntityManager().getCriteriaBuilder().greaterThanOrEqualTo(r.<java.util.Date>get(where.get("name").toString()),value0);
      }
      else if(where.get("where").toString().equals("lessThanOrEqualTo"))
      {
        java.util.Date value0=(java.util.Date)where.get("value0");
        p = getEntityManager().getCriteriaBuilder().lessThanOrEqualTo(r.<java.util.Date>get(where.get("name").toString()),value0);
      }

    }
  }
  Predicate[] predicates = new Predicate[predicateList.size()];
  predicateList.toArray(predicates);
  cq.where(predicates);

  if(orderBy!= null&& !orderBy.equals("")){
    if(orderBy.endsWith("desc"))
      cq.orderBy(getEntityManager().getCriteriaBuilder().desc(r.get(orderBy.substring(0,orderBy.indexOf(" ")))));
    else
      cq.orderBy(getEntityManager().getCriteriaBuilder().asc(r.get(orderBy.substring(0,orderBy.indexOf(" ")))));
  }

  javax.persistence.Query q = getEntityManager().createQuery(cq);
  if(range!=null){
    q.setMaxResults(range[1] - range[0]);
    q.setFirstResult(range[0]);
  }
  return q.getResultList();
}

1) "Величайший" метод возвращает эту ошибку:

p = getEntityManager().getCriteriaBuilder().and(getEntityManager().getCriteriaBuilder().greatest(r.<Long>get(where.get("name").toString())));
method CriteriaBuilder.and(Expression<Boolean>,Expression<Boolean>) is not applicable
(actual and formal argument lists differ in length)
method CriteriaBuilder.and(Predicate...) is not applicable
(argument type Expression<Long> does not conform to vararg element type Predicate)

и я ищу пример для этого метода, но не нашел ничего полезного;

2) как я уже писал, мой HashMapp также содержит класс поля, который я хочу отфильтровать, теперь я бы использовал эту информацию для перезаписи между, GreaterThanOrEqualTo, lessThanOrEqualTo, поэтому, если бы я хотел, я мог бы фильтровать некоторые другие типы, чем java.util. Дата! Что вы думаете об этом длинном вопросе? Спасибо за помощь!

P.S.: Извините за мой не идеальный английский, но я итальянец.

P.S.2: Извините также за структуру моего кода... Я слепой и не всегда контролирую отступы... этот сайт контролирует их, но я не уверен, что правильно делаю отступы во всем коде!

java

Ответы

Ответ 1 · рейтинг 2 · JB Nizet

ИМХО, это не лучшая идея. Вы заново изобретаете новый общий язык запросов, и этот новый язык запросов будет

  • менее выразительный, чем JPQL
  • нестандартный
  • менее типобезопасен, чем Criteria API
  • менее эффективен, чем JPQL и Criteria

Итак, ответы на ваши вопросы

  1. Нет, это не очень хорошая идея.
  2. Да, такая структура уже существует. Он называется JPQL.

Ответ 2 · рейтинг 1 · tglman

Я не думаю, что создание метода, который использует строку для построения запроса с помощью Criteria API, является хорошей идеей, я определенно предлагаю использовать JPQL или, если вы предпочитаете какой-либо другой инструмент, который поможет вам построить запрос самым разумным образом, вы можете использовать : ObjectQuery или Query Dsl. или Torpedo Query, если вы хотите изолировать свой код от фактической реализации, подумайте о том, чтобы скрыть запрос внутри некоторого DAO. или объект репозитория, или хотя бы создайте оболочку над каким-нибудь построителем запросов!

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы