Создать динамический SQL запрос

223
24 июня 2018, 03:50

Мне надо построить динамический SQL-запрос, по которому будет осуществляться поиск объектов в базе данных. Поиск должен производится по фильтру, в котором несколько параметров для поиска. У меня есть готовые таблицы, класс Filterс конструкторами и геттерами. Вот класс DAOс методами поиска и составления запроса:

public class RoomDAO extends GeneralDAO<Room> {
    private static final String SQL_GET_ROOM_BY_ID = "SELECT * FROM ROOM WHERE ID = :idParam";
    private static final String NATIVE_SQL_GET_ROOMS_BY_FILTER = "SELECT * FROM ROOM r, HOTEL h WHERE h.ID = r.ID_HOTEL AND BREAKFAST_INCLUDED = :brParam AND PETS_ALLOWED = :petParam";
    @SuppressWarnings("unchecked")
    public Collection<Room> findRooms(Filter filter){
        try(Session session = createSessionFactory().openSession()){
            NativeQuery<Room> roomQuery = session.createNativeQuery(createQuery(filter));
            roomQuery.setParameter("brParam", filter.isBreakfastIncluded());
            roomQuery.setParameter("petParam", filter.isPetsAllowed());
            roomQuery.list();
            return (Collection<Room>) roomQuery;
        }
    }
    public String createQuery(Filter filter){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(NATIVE_SQL_GET_ROOMS_BY_FILTER);
        if (filter.getNumberOfGuests() != 0)
            stringBuilder.append(" AND r.NUMBER_OF_GUESTS = ").append(filter.getNumberOfGuests());
        if (filter.getPrice() != 0)
            stringBuilder.append(" AND r.PRICE = ").append(filter.getPrice());
        if (filter.getDateAvailableFrom() != null)
            stringBuilder.append(" AND r.DATE_AVAILABLE_FROM = ").append(filter.getDateAvailableFrom());
        if (filter.getCountry() != null)
            stringBuilder.append(" AND h.COUNTRY = '").append(filter.getCountry()).append("'");
        if (filter.getCity() != null)
            stringBuilder.append(" AND h.CITY = '").append(filter.getCity()).append("'");
        return String.valueOf(stringBuilder);
    }
}

И вот какая падает ошибка при проверке работы метода поиска:

"C:\Program Files\Java\jdk1.8.0_111\bin\java" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2018.1\lib\idea_rt.jar=64968:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2018.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar;C:\Users\Skorodielov\IdeaProjects\javajdbcgrom\target\classes;C:\Users\Skorodielov\.m2\repository\com\oracle\ojdbc7\12.1.0\ojdbc7-12.1.0.jar;C:\Users\Skorodielov\.m2\repository\org\hibernate\hibernate-core\5.2.16.Final\hibernate-core-5.2.16.Final.jar;C:\Users\Skorodielov\.m2\repository\org\jboss\logging\jboss-logging\3.3.1.Final\jboss-logging-3.3.1.Final.jar;C:\Users\Skorodielov\.m2\repository\org\hibernate\javax\persistence\hibernate-jpa-2.1-api\1.0.0.Final\hibernate-jpa-2.1-api-1.0.0.Final.jar;C:\Users\Skorodielov\.m2\repository\org\javassist\javassist\3.22.0-GA\javassist-3.22.0-GA.jar;C:\Users\Skorodielov\.m2\repository\antlr\antlr\2.7.7\antlr-2.7.7.jar;C:\Users\Skorodielov\.m2\repository\org\jboss\spec\javax\transaction\jboss-transaction-api_1.2_spec\1.0.1.Final\jboss-transaction-api_1.2_spec-1.0.1.Final.jar;C:\Users\Skorodielov\.m2\repository\org\jboss\jandex\2.0.3.Final\jandex-2.0.3.Final.jar;C:\Users\Skorodielov\.m2\repository\com\fasterxml\classmate\1.3.0\classmate-1.3.0.jar;C:\Users\Skorodielov\.m2\repository\dom4j\dom4j\1.6.1\dom4j-1.6.1.jar;C:\Users\Skorodielov\.m2\repository\org\hibernate\common\hibernate-commons-annotations\5.0.1.Final\hibernate-commons-annotations-5.0.1.Final.jar" hibernate_dz.dz_lesson4.demo.RoomDemo
июн 01, 2018 4:01:08 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {5.2.16.Final}
июн 01, 2018 4:01:08 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
июн 01, 2018 4:01:08 PM org.hibernate.boot.jaxb.internal.stax.LocalXmlResourceResolver resolveEntity
WARN: HHH90000012: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/hibernate-configuration. Use namespace http://www.hibernate.org/dtd/hibernate-configuration instead.  Support for obsolete DTD/XSD namespaces may be removed at any time.
июн 01, 2018 4:01:08 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
июн 01, 2018 4:01:08 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!)
июн 01, 2018 4:01:09 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: using driver [oracle.jdbc.driver.OracleDriver] at URL [jdbc:oracle:thin:@gromcode-lesson.cjqbbseqr63c.eu-central-1.rds.amazonaws.com:1521:ORCL]
июн 01, 2018 4:01:09 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {user=main, password=****}
июн 01, 2018 4:01:09 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
июн 01, 2018 4:01:09 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
июн 01, 2018 4:01:09 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
Hibernate: SELECT * FROM ROOM r, HOTEL h WHERE h.ID = r.ID_HOTEL AND BREAKFAST_INCLUDED = ? AND PETS_ALLOWED = ? AND r.PRICE = 175.0
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.loader.custom.NonUniqueDiscoveredSqlAliasException: Encountered a duplicated sql alias [ID] during auto-discovery of a native-sql query
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:149)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157)
    at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1423)
    at hibernate_dz.dz_lesson4.dao.RoomDAO.findRooms(RoomDAO.java:28)
    at hibernate_dz.dz_lesson4.demo.RoomDemo.main(RoomDemo.java:51)
Caused by: org.hibernate.loader.custom.NonUniqueDiscoveredSqlAliasException: Encountered a duplicated sql alias [ID] during auto-discovery of a native-sql query
    at org.hibernate.loader.custom.CustomLoader.validateAliases(CustomLoader.java:508)
    at org.hibernate.loader.custom.CustomLoader.autoDiscoverTypes(CustomLoader.java:485)
    at org.hibernate.loader.Loader.processResultSet(Loader.java:2214)
    at org.hibernate.loader.Loader.getResultSet(Loader.java:2170)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1931)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1893)
    at org.hibernate.loader.Loader.doQuery(Loader.java:938)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:341)
    at org.hibernate.loader.Loader.doList(Loader.java:2692)
    at org.hibernate.loader.Loader.doList(Loader.java:2675)
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2507)
    at org.hibernate.loader.Loader.list(Loader.java:2502)
    at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:335)
    at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2161)
    at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:1016)
    at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:152)
    at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1414)
    ... 2 more
Process finished with exit code -1

Пробовал делать запрос и без псевдонимов таблиц, ошибка такая же падает. Подскажите, как я могу это исправить в этом варианте ?

Структура таблиц HOTEL и ROOM:

CREATE TABLE HOTEL(
ID NUMBER NOT NULL PRIMARY KEY,
NAME NVARCHAR2(20) NOT NULL,
COUNTRY NVARCHAR2(20) NOT NULL,
CITY NVARCHAR2(20) NOT NULL,
STREET NVARCHAR2(20) NOT NULL
);
CREATE TABLE ROOM(
ID NUMBER NOT NULL PRIMARY KEY,
ID_HOTEL NUMBER,
CONSTRAINT ROOM_FK FOREIGN KEY(ID_HOTEL)REFERENCES HOTEL(ID) ON DELETE SET NULL,
NUMBER_OF_GUESTS NUMBER NOT NULL,
PRICE NUMBER(*, 2) NOT NULL,
BREAKFAST_INCLUDED NUMBER CHECK (BREAKFAST_INCLUDED = 1 OR BREAKFAST_INCLUDED = 0),
PETS_ALLOWED NUMBER CHECK (PETS_ALLOWED = 1 OR PETS_ALLOWED = 0),
DATE_AVAILABLE_FROM TIMESTAMP NOT NULL
);
Answer 1

У вас в обоих таблицах есть поле ID и поскольку вы используете * для имен полей, то поле ID попадает два раза в результат. В связи с чем hibernate ругается на дублирование алиаса.

Чтобы это исправить надо переименовать алиасы для двух таблиц, которые вы джойните, чтобы небыло совпадений.

READ ALSO
Перемещение между графиками Jfreechart

Перемещение между графиками Jfreechart

Есть графики (до 100 штук), каждый график должен быть отдельно (то есть на экране по 1 линии), как можно реализовать перемещение между графиками?...

212
ссылка на дженерик

ссылка на дженерик

Почему такая запись функционирует? i2 уже ждет object в параметрах add, а не стрингиОт чего это происходит?

218
Как передать информацию в аннотацию?

Как передать информацию в аннотацию?

Использую кастомную аннотацию @Example("objectName"), которая переносит нужную информацию - "objectName"Задался спортивным вопросом - как в аннотацию передать...

209
Медленно работает Callable

Медленно работает Callable

Столкнулся с проблемой: медленно выполняется программа, использующая CallableВернее так: ответ выдается сразу, но потом она очень долго думает...

221