Репозиторий Spring Data и собственный запрос с типом возвращаемого значения Geometry - PullRequest
0 голосов
/ 14 сентября 2018

Я создаю проект, который использует некоторые пространственные запросы. Я использую Spring boot с репозиториями данных Spring и PostgreSQL с расширением PostGIS в качестве базы данных.

Я создал этот репозиторий:

import com.vividsolutions.jts.geom.Geometry;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface AreaRepository extends CrudRepository<Area, Long> {

    /*
      extra queries for Area here
    */

    @Query(value="select st_intersection(" +
                ":base_layer ," +
                ":filter_layer" +
                ")", nativeQuery = true)
    Geometry geometryIntersectGeometry(@Param("base_layer") Geometry baseGeometry,@Param("filter_layer") Geometry filterGeometry);

}

Содержит несколько запросов для объекта Area. Я также хочу использовать некоторые функции PostGIS для выполнения некоторых вычислений, поэтому я создал geometryIntersectGeometry для вызова функции st_intersection из PostGis, которая должна вернуть геометрию.

Я установил спящий диалект на PostGIS в настройках:

spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/test_db
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.properties.hibernate.dialect = org.hibernate.spatial.dialect.postgis.PostgisDialect

И у меня есть зависимости для спящего пространства:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-spatial</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        ...

Вызов функции geometryIntersectGeometry приводит к ошибке:

No Dialect mapping for JDBC type: 1111; nested exception is org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111,{}

Как мне указать JPA / Spring Data для сопоставления ответа геометрии (типа PostGIS) с объектом Geometry (com.vividsolutions.jts.geom.Geometry)?

Ответы [ 3 ]

0 голосов
/ 14 сентября 2018

Удалось исправить это, написав пользовательскую реализацию хранилища и зарегистрировать тип (спасибо Саймону Мартинелли)

Репозиторий:

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface AreaRepository extends CrudRepository<Area, Long>, AreaGisRepository {

    /*
      extra queries for Area here
    */

}

Интерфейс:

import com.vividsolutions.jts.geom.Geometry;

public interface AreaGisRepository {

    Geometry geometryIntersectGeometry(Geometry baseGeometry, Geometry filterGeometry);
}

и реализация:

import com.vividsolutions.jts.geom.Geometry;
import org.hibernate.spatial.JTSGeometryType;
import org.hibernate.spatial.dialect.postgis.PGGeometryTypeDescriptor;
import org.springframework.beans.factory.annotation.Autowired;

import javax.persistence.EntityManager;

public class AreaGisRepositoryImpl implements AreaGisRepository {

    private EntityManager entityManager;

    @Autowired
    public AreaGisRepositoryImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public Geometry geometryIntersectGeometry(Geometry baseGeometry, Geometry filterGeometry) {
        return (Geometry) entityManager
                .createNativeQuery(
                        "select st_intersection(:base_layer , :filter_layer) as geom")
                .setParameter("base_layer", baseGeometry)
                .setParameter("filter_layer", filterGeometry)
                .unwrap(org.hibernate.query.NativeQuery.class)
                .addScalar("geom", new JTSGeometryType(PGGeometryTypeDescriptor.INSTANCE))
                .getSingleResult();
    }

}

Это прекрасно работает, но теперь у меня есть жестко закодированная зависимость от Postgis (вряд ли мы будем использовать что-то еще, но ...)

0 голосов
/ 16 сентября 2018

Я думаю, что есть более простой способ сделать это. Hibernate Spatial регистрирует ряд пространственных функций для использования в HQL / JQL. Таким образом, следующее должно работать

@Query(value="select intersection(" +
            ":base_layer ," +
            ":filter_layer" +
            ")")
Geometry geometryIntersectGeometry(@Param("base_layer") Geometry baseGeometry,@Param("filter_layer") Geometry filterGeometry);

См. документацию для списка функций, доступных в Пространственных Диалектах.

0 голосов
/ 14 сентября 2018

Вы добавили Hibernate Spatial?

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-spatial</artifactId>
    <version>${hibernate.version}</version>
</dependency>

Это поддерживает данные ГИС: http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#spatial

...