【问题标题】:Using JPA Criteria Api and hibernate spatial 4 together一起使用 JPA Criteria Api 和 hibernate spatial 4
【发布时间】:2013-09-20 06:08:06
【问题描述】:

这里给出查询示例: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) 部分。

【问题讨论】:

    标签: java hibernate jpa criteria-api hibernate-spatial


    【解决方案1】:

    我最近在处理完全相同的问题。我的解决方案是为 within-keyword 创建一个自己的谓词。

        public class WithinPredicate extends AbstractSimplePredicate implements Serializable {
        private final Expression<Point> matchExpression;
        private final Expression<Geometry> area;
    
        public WithinPredicate(CriteriaBuilderImpl criteriaBuilder, Expression<Point> matchExpression, Geometry area) {
            this(criteriaBuilder, matchExpression, new LiteralExpression<Geometry>(criteriaBuilder, area));
        }
        public WithinPredicate(CriteriaBuilderImpl criteriaBuilder, Expression<Point> matchExpression, Expression<Geometry> area) {
            super(criteriaBuilder);
            this.matchExpression = matchExpression;
            this.area = area;
        }
    
        public Expression<Point> getMatchExpression() {
            return matchExpression;
        }
    
        public Expression<Geometry> 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<Event> findEventInArea(Geometry area){
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Event> c = cb.createQuery(Event.class);
    
        Root<Event> event = c.from(Event.class);
        c.where(new WithinPredicate((CriteriaBuilderImpl) cb, event.get(Event_.location), area));
        Query query = entityManager.createQuery(c);
        return query.getResultList();
    }
    

    【讨论】:

      【解决方案2】:

      JPA 不支持空间。但是,您可以从 JPA EntityManager 中解开休眠会话并运行空间标准。

      此代码示例中的纬度范围是任意的。

      @PersistenceContext(unitName = "myPuName")
      private EntityManager entityManager;
      
      @Override
      public List<City> 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;
      }
      

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

      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)";
          }
      }
      

      【讨论】:

        【解决方案3】:

        在 JPA2 中,您可以使用函数表达式生成器。不再需要专门的东西。也适用于订单表达式。

        public List<Event> listThem(Geometry area) {
            CriteriaBuilder cb = em.getCriteriaBuilder();
            CriteriaQuery<Event> cq = cb.createQuery(Event.class);
            Root<Event> root = cq.from(Event.class);
            ParameterExpression<Geometry> circleParm = cb.parameter(Geometry.class);
            cq.where(cb.isTrue(cb.function("st_within", Boolean.class, 
                                           root.get(Event_.location), circleParm)));
            TypedQuery<Event> tq = em.createQuery(cq);
            tq.setParameter(circleParm, area);
            return tq.getResultList();
        }
        

        小价:函数名依赖于数据库。在 PostgreSQL 中,within 函数称为 st_within。

        【讨论】:

        • 如何创建在参数中传递的几何区域?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-21
        • 2019-03-28
        • 2016-09-02
        • 2015-09-18
        • 2017-03-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多