4

I tried to use spatial API in Spring boot.

  • I am able to save the SDO_GEOMETRY data types into oracle database.
  • I am able to retrieve it using SQL query,
  • Only problem is If I use with Hibernate APIs it throws an error (don't want to use SQL)

I tested following SQL query it works fine, so the problem not in database

SELECT
    s.ID,
    s.LOCATION
FROM PORTS s
where SDO_WITHIN_DISTANCE(
              s.LOCATION,
              SDO_GEOMETRY(2001, 8307,
                           SDO_POINT_TYPE( 24.817768,46.599417, NULL),NULL, NULL
                  ),
              'distance=10 unit=KM'
          ) = 'TRUE';

My Entity:

@Entity
@Table(name = "ports")
@Getter @Setter
@NoArgsConstructor
public class JpaPort {
    @Id
    @Column(name = "id", unique = true, nullable = false, insertable = false, updatable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
 @Column(name = "location",columnDefinition="SDO_GEOMETRY")
    private Geometry location;
    private String name;
}

My repository query:

 portRepository.findAll(filterWithinRadius(portDTO.getLat(), portDTO.getLon(), portDTO.getRangeInMeters()));

Specification for this:

public static Specification<JpaPort> filterWithinRadius(double latitude, double longitude, double radius) {
        return new Specification<JpaPort>() {
            @Override
            public Predicate toPredicate(Root<JpaPort> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                GeometryFactory factory = new GeometryFactory();

                Geometry comparisonPoint = factory.createPoint(new Coordinate(latitude,longitude));

                comparisonPoint.setSRID(8307);

               Expression<Geometry> dbPoint = root.get("location").as(Geometry.class);
                Expression<Boolean> expression = builder.function("SDO_WITHIN_DISTANCE", boolean.class,
                        dbPoint, builder.literal(comparisonPoint),builder.literal("DISTANCE=1 UNIT=MILE"));
                return builder.equal(expression, true);
            }
        };
    }

If I'm using Hibernate I got following error

 Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet] with root cause

 oracle.jdbc.OracleDatabaseException: ORA-01722: invalid number

I don't know my this approach is correct/wrong, because I'm new to spring development, if you have any other solution feel free to answer or comment.

Is there any other way to make the Spatial API query in Hibernate?

My source code - https://drive.google.com/file/d/1loSLFg3Cok9iwtv3apXP3f59QiJdI2eS/view?usp=sharing

3
  • 2
    return builder.equal(expression, true) - there is no boolean datatype in oracle, moreover, your initial SQL deals with varchar 'TRUE' Commented Aug 10, 2022 at 20:19
  • @Olivier ok got it. I'm new to spring development. I added the JPA tag Commented Aug 13, 2022 at 7:57
  • Now you should follow Andrey's advice and fix the return type of SDO_WITHIN_DISTANCE(). Commented Aug 13, 2022 at 8:06

1 Answer 1

2
+100

You have to compare the result against the varchar 'TRUE', just like in your SQL example. Use this:

Expression<String> expression = builder.function("SDO_WITHIN_DISTANCE", String.class,
    dbPoint, builder.literal(comparisonPoint),builder.literal("DISTANCE=1 UNIT=MILE"));
return builder.equal(expression, "TRUE");
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.