Hibernate и Postgres: функция st_buffer (bytea, numeric) не уникальна

Я работаю с Hibernate 5.1.0 в приложении Java. Я подключаюсь как к Postgres 9.5 с Postgis расширениями, так и к Oracle базам данных. Мне нужно найти все геометрии в моей базе данных, которые пересекаются с заданной геометрией, к которой я применяю буфер, например:

Query query = session
            .createQuery("select b from Block b where intersects(b.geom, buffer(:geometry, " + bufferDistance + ")) = "
                    + UtilsHelper.getTrueBooleanValue(em));
query.setParameter("geometry", geom);
List<Block> blocks = query.list();

Это работает в Oracle, но в Postgres я получу ошибку:

Caused by: org.postgresql.util.PSQLException: ERROR: function st_buffer(bytea, numeric) is not unique
Hint: Could not choose a best candidate function. You might need to add explicit type casts.
Position: 243
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2270)

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

geometry ST_Buffer(geometry g1, float radius_of_buffer);
geography ST_Buffer(geography g1, float radius_of_buffer_in_meters);

UtilsHelper.getTrueBooleanValue(em) просто получит правильное логическое значение в зависимости от менеджера сущностей, то есть 0/1 для Oracle и true/false для Postgres.

Одним из очевидных решений было бы отказаться от одной из функций. Кроме этого, есть ли способ исправить это?


person krause    schedule 31.05.2016    source источник


Ответы (1)


Я не утверждаю, что много знаю о Hibernate, но кажется, что простое решение — явно преобразовать bytea с CAST(:geometry AS geometry) и модернизировать остальной запрос, добавив префикс "ST_", который используется в более новых версиях PostGIS.

Что еще более важно, вы никогда не должны писать запрос с формой:

SELECT b
FROM Block b
WHERE ST_Intersects(b.geom, ST_Buffer(CAST(:geometry AS geometry), :bufferDistance)) = TRUE;

Использование буфера для выбора области медленнее и несовершеннее, чем использование основанной на расстоянии функции ST_DWithin для поиска геометрии, которые находятся на расстоянии. ST_DWithin также может использовать пространственный индекс, если он доступен. И логический оператор не должен иметь часть = + UtilsHelper.getTrueBooleanValue(em) (т.е. TRUE = TRUE это TRUE). Просто удалите его.

Попробуйте написать функцию, которая больше похожа на:

SELECT b
FROM Block b
WHERE ST_Dwithin(b.geom, CAST(:geometry AS geometry), :distance);

(используя два параметра :geometry и :distance)

person Mike T    schedule 01.06.2016
comment
Спасибо за ваш ответ, Майк Т. Я пытаюсь заставить его работать с этим CAST. В любом случае, это, вероятно, будет хорошо только для Postgres, а не для Oracle. Как уже отмечалось, мне нужно, чтобы это работало с обеими БД. Именно поэтому я полагаюсь на Hibernate для генерации фактического запроса, будь то ST_Buffer или любой префикс ST_ для Postgres или эквивалент SDO в Oracle. - person krause; 09.06.2016
comment
@krause снова я не знаком с Hibernate, но у Oracle есть SDO_WITHIN_DISTANCE, что эквивалентно ST_DIn, упомянутому выше. - person Mike T; 10.06.2016