8

ここでクエリの例を考える: 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)部分をどのように処理すればよいかわかりません。

4

3 に答える 3

12

私は最近、まったく同じ問題に取り組んでいます。私の解決策は、キーワード内の独自の述語です。

    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();
}
于 2014-07-29T19:23:48.367 に答える
9

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)";
    }
}
于 2014-03-27T13:24:44.143 に答える
0

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 では、inside 関数は st_within と呼ばれます。

于 2020-09-24T07:46:51.350 に答える