Ищете HQL-конструктор (Hibernate Query Language) - PullRequest
7 голосов
/ 11 сентября 2008

Я ищу конструктор для HQL в Java. Я хочу избавиться от таких вещей, как:

StringBuilder builder = new StringBuilder()
    .append("select stock from ")
    .append( Stock.class.getName() )
    .append( " as stock where stock.id = ")
    .append( id );

Я бы предпочел что-то вроде:

HqlBuilder builder = new HqlBuilder()
    .select( "stock" )
    .from( Stock.class.getName() ).as( "stock" )
    .where( "stock.id" ).equals( id );

Я немного погуглил и не смог найти.

Я написал быстрый и тупой HqlBuilder, который в настоящее время соответствует моим потребностям, но я бы хотел найти тот, у которого будет больше пользователей и тестов, чем у меня одного.

Примечание: я хотел бы иметь возможность делать такие вещи и многое другое, чего я не смог сделать с Criteria API:

select stock
from com.something.Stock as stock, com.something.Bonus as bonus
where stock.someValue = bonus.id

т. выберите все акции, чье свойство someValue указывает на любой бонус из таблицы бонусов.

Спасибо!

Ответы [ 11 ]

6 голосов
/ 11 сентября 2008

Разве Criteria API не делает это для вас? Это выглядит почти так же, как то, что вы просите.

6 голосов
/ 12 января 2010

Для безопасного типа решения вашей проблемы рассмотрим Querydsl .

Пример запроса становится

HQLQuery query = new HibernateQuery(session);
List<Stock> s = query.from(stock, bonus)
  .where(stock.someValue.eq(bonus.id))
  .list(stock);

Querydsl использует APT для генерации кода, такого как JPA2, и поддерживает коллекции JPA / Hibernate, JDO, SQL и Java.

Я поддерживаю Querydsl, поэтому этот ответ предвзят.

5 голосов
/ 04 декабря 2011

Для другого запроса на безопасность типов dsl я рекомендую http://www.torpedoquery.org. Библиотека еще молодая, но обеспечивает безопасность типов, напрямую используя классы вашей сущности. Это означает ранние ошибки компилятора, когда запрос больше не применяется до рефакторинга или перепроектирования.

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

import static org.torpedoquery.jpa.Torpedo.*;

Bonus bonus = from(Bonus.class);
Query subQuery = select(bonus.getId());

Stock stock = from(Stock.class);
where(stock.getSomeValue()).in(subQuery);

List<Stock> stocks = select(stock).list(entityManager);
4 голосов
/ 11 сентября 2008

@ Себастьян Рокка-Серра
Теперь мы получаем что-то конкретное. Такое объединение, которое вы пытаетесь выполнить, на самом деле невозможно с помощью API Criteria, но подзапрос должен выполнить то же самое. Сначала вы создаете DetachedCriteria для бонусной таблицы, затем используйте оператор IN для someValue.

DetachedCriteria bonuses = DetachedCriteria.forClass(Bonus.class);
List stocks = session.createCriteria(Stock.class)
    .add(Property.forName("someValue").in(bonuses)).list();

Это эквивалентно

select stock
from com.something.Stock as stock
where stock.someValue in (select bonus.id from com.something.Bonus as bonus)

Единственный недостаток - если у вас есть ссылки на разные таблицы в someValue, а ваши идентификаторы не уникальны для всех таблиц. Но ваш запрос будет страдать от того же недостатка.

4 голосов
/ 11 сентября 2008

Похоже, вы хотите использовать API запроса Criteria, встроенный в Hibernate. Для выполнения вышеуказанного запроса это будет выглядеть так:

List<Stock> stocks = session.createCriteria(Stock.class)
    .add(Property.forName("id").eq(id))
    .list();

Если у вас еще нет доступа к Hibernate Session, вы можете использовать 'DetachedCriteria' следующим образом:

DetachedCriteria criteria = DetachedCriteria.forClass(Stock.class) 
    .add(Property.forName("id").eq(id));

Если вы хотите получить все акции, имеющие бонус с определенным идентификатором, вы можете сделать следующее:

DetachedCriteria criteria = DetachedCriteria.forClass(Stock.class)
     .createCriteria("Stock")
          .add(Property.forName("id").eq(id)));

Для получения дополнительной информации ознакомьтесь с Критериями запросов из документов Hibernate

2 голосов
/ 10 декабря 2009

Я знаю, что эта ветка довольно старая, но я также искал HqlBuilder, и я нашел этот проект "заставки"
Это НЕ заставка Windows, это « Лабораторная информационная система управления (LIMS) для высокопроизводительных скрининговых устройств (HTS), которые выполняют скрининг малых молекул и РНКи. Содержит HQLBuilder, который выглядит неплохо.
Вот примерный список доступных методов:

...
HqlBuilder select(String alias);
HqlBuilder select(String alias, String property);
HqlBuilder from(Class<?> entityClass, String alias);
HqlBuilder fromFetch(String joinAlias, String joinRelationship, String alias);
HqlBuilder where(String alias, String property, Operator operator, Object value);
HqlBuilder where(String alias, Operator operator, Object value);
HqlBuilder where(String alias1, Operator operator, String alias2);
HqlBuilder whereIn(String alias, String property, Set<?> values);
HqlBuilder whereIn(String alias, Set<?> values);
HqlBuilder where(Clause clause);
HqlBuilder orderBy(String alias, String property);
HqlBuilder orderBy(String alias, SortDirection sortDirection);
HqlBuilder orderBy(String alias, String property, SortDirection sortDirection);
String toHql();
...
2 голосов
/ 02 декабря 2009

Посмотрите на пакет поиска, доступный в проекте hibernate-generic-dao . Это довольно приличная реализация HQL Builder.

2 голосов
/ 25 февраля 2009

Я написал GPL-решение для OMERO, которое вы могли бы легко построить в соответствии с вашей ситуацией.

Использование:

QueryBuilder qb = new QueryBuilder();
qb.select("img");
qb.from("Image", "img");
qb.join("img.pixels", "pix", true, false);

// Can't join anymore after this
qb.where(); // First
qb.append("(");
qb.and("pt.details.creationTime > :time");
qb.param("time", new Date());
qb.append(")");
qb.and("img.id in (:ids)");
qb.paramList("ids", new HashSet());
qb.order("img.id", true);
qb.order("this.details.creationEvent.time", false);

Он функционирует в качестве конечного автомата "select-> from-> join-> where-> order" и т. Д. И поддерживает дополнительные параметры. Было несколько запросов, которые API-интерфейс Criteria не мог выполнить (см. HHH-879 ), поэтому в итоге было проще написать этот небольшой класс для переноса StringBuilder. (Примечание: есть билет HHH-2407 , описывающий ветку Hibernate, который должен объединить их. После этого, вероятно, имеет смысл повторно посетить API Criteria)

2 голосов
/ 11 сентября 2008

Criteria API не предоставляет всех функциональных возможностей, доступных в HQL. Например, вы не можете сделать более одного объединения в одном столбце.

Почему бы вам не использовать ИМЕННЫЕ ЗАПРОСЫ ? Выглядит намного чище:

Person person = session.getNamedQuery("Person.findByName")
                             .setString(0, "Marcio")
                             .list();
2 голосов
/ 11 сентября 2008

@ Себастьян Рокка-Серра

select stock
from com.something.Stock as stock, com.something.Bonus as bonus
where stock.bonus.id = bonus.id

Это просто соединение. Hibernate делает это автоматически, если и только если у вас есть соответствие между настройками Stock и Bonus и если bonus является свойством Stock. Criteria.list() вернет Stock объектов, и вы просто позвоните stock.getBonus().

Обратите внимание, если вы хотите сделать что-то вроде

select stock
from com.something.Stock as stock
where stock.bonus.value > 1000000

Вам необходимо использовать Criteria.createAlias(). Это было бы что-то вроде

session.createCriteria(Stock.class).createAlias("bonus", "b")
   .add(Restrictions.gt("b.value", 1000000)).list()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...