使用JPA Criteria Api和hibernate spatial 4

鉴于这里的查询示例: http : //www.hibernatespatial.org/tutorial-hs4.html

Query query = em.createQuery("select e from Event e where within(e.location, :filter) = true", Event.class); query.setParameter("filter", filter); 

是否可以使用jpa 2条件api重写查询?(我不确定我应该如何处理within(e.location, :filter)部分。

JPA不支持空间。 但是,您可以从JPA EntityManager中解包hibernate会话并运行空间条件。

此代码示例中的lat lon边界是任意的。

 @PersistenceContext(unitName = "myPuName") private EntityManager entityManager; @Override public List findCities() { CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); Session session = entityManager.unwrap(Session.class); Criteria criteria = session.createCriteria(City.class); GeometryFactory geometryFactory = new GeometryFactory(); Coordinate[] coordinates = {new Coordinate(-9,-9,0),new Coordinate(-9,9,0),new Coordinate(9,9,0),new Coordinate(9,-9,0),new Coordinate(-9,-9,0)}; LinearRing polygon = geometryFactory.createLinearRing(coordinates); Polygon po = geometryFactory.createPolygon(polygon,null); criteria.add(SpatialRestrictions.within(City_.location.getName(), po)); List list = criteria.list(); return list; } 

这里有一些与问题没有直接关系的代码。 此类可以用作要添加到hibernate标准的“Order”条件。 它将按参数位置的距离对结果进行排序:

 public class KnnOrder extends Order { private final Point fromPoint; public KnnOrder(String propertyName, boolean ascending, Point fromPoint) { super(propertyName, ascending); this.fromPoint = fromPoint; } @Override public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) { Dialect dialect = criteriaQuery.getFactory().getDialect(); if (!dialect.getClass().isAssignableFrom(PostgisDialect.class)) { throw new UnsupportedOperationException("This supports only postgis dialect. Was requested: " + dialect.toString()); } // final String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, super.getPropertyName()); // String fromPointWkt = WKTWriter.toPoint(fromPoint.getCoordinate()); return "location <-> st_setsrid(st_makepoint(" + fromPoint.getX() + "," + fromPoint.getY() + "),4326)"; } } 

我最近在完全相同的问题上工作。 我的解决方案是内部关键字的自己谓词。

  public class WithinPredicate extends AbstractSimplePredicate implements Serializable { private final Expression matchExpression; private final Expression area; public WithinPredicate(CriteriaBuilderImpl criteriaBuilder, Expression matchExpression, Geometry area) { this(criteriaBuilder, matchExpression, new LiteralExpression(criteriaBuilder, area)); } public WithinPredicate(CriteriaBuilderImpl criteriaBuilder, Expression matchExpression, Expression area) { super(criteriaBuilder); this.matchExpression = matchExpression; this.area = area; } public Expression getMatchExpression() { return matchExpression; } public Expression getArea() { return area; } public void registerParameters(ParameterRegistry registry) { // Nothing to register } @Override public String render(boolean isNegated, RenderingContext renderingContext) { StringBuilder buffer = new StringBuilder(); buffer.append(" within(") .append(((Renderable) getMatchExpression()).render(renderingContext)) .append(", ") .append(((Renderable) getArea()).render(renderingContext)) .append(") = true "); return buffer.toString(); } } 

您的查询将如下所示:

 public List findEventInArea(Geometry area){ CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery c = cb.createQuery(Event.class); Root event = c.from(Event.class); c.where(new WithinPredicate((CriteriaBuilderImpl) cb, event.get(Event_.location), area)); Query query = entityManager.createQuery(c); return query.getResultList(); }