2013-09-16 4 views
4

Учитывая пример запроса здесь: http://www.hibernatespatial.org/tutorial-hs4.htmlИспользование JPA Критерии Апи и спящий режим пространственного 4 вместе

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)? часть.

ответ

4

JPA не поддерживает пространственными. Однако, вы можете разворачивать гибернации сессию вашей JPA EntityManager и запустить пространственные критерии.

The Lat Lon оценок в этом примере кода является произвольным.

@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

Я недавно работал над той же проблемой. Мое решение - это собственный предикат для ключевого слова внутри.

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