Specification/Predicate for Hibernate/spatial 过滤实体是否在半径内
Specification/Predicate for Hibernate/spatial to filter an Entity whether it is in radius or not
我想在 Predicate/Specification 中重写以下查询,以便我可以 link 它们。
此查询过滤我在特定区域内定义的所有 OptEvent 实体
@Query(value = "SELECT * FROM opt_event WHERE ST_DWithin(cast(opt_event.locationpoint as geography),ST_SetSRID(ST_Point(?2, ?1),4326), 100000);", nativeQuery = true)
public Set<OptEvent> findAllEventsInRange(double longitude, double latitude);
一般我都是这样写规范的,以后可以串起来。取决于是否应用过滤器。
public static Specification<OptEvent> filterArea(Double longitude, Double latitude) {
return new Specification<OptEvent>() {
@Override
public Predicate toPredicate(Root<OptEvent> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
SpatialRelateExpression geomExpression = SpatialRestrictions.within("locationpoint ", area);
//this is the only thing i could find, but i have no idea if its the right path or how i can transform it to the Specification
// what is area ?
//Example when i filter for the destination in the OptEvent
//return (root, query, builder) -> builder.like(builder.upper(root.get("destination")),
//"%" + destination.toUpperCase() + "%");
}
};
}
有关我的环境的更多信息。
我的 pom 下面。我使用 Postgres 和 Hibernate 5.4.10.Final.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
//Version 5.4.10 FINAL from Hibernate-Core
</dependency>
<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<version>1.13</version>
</dependency>
</dependencies>
对于我的定位点,我使用 org.locationtech.jts.geom.Point;
@Entity
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class OptEvent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String destination;
private String description;
private int year;
private EventSeries eventSeries;
private LocalDate eventDate;
@JsonSerialize(using = GeometrySerializer.class)
@JsonDeserialize(contentUsing = GeometryDeserializer.class)
private Point locationpoint;
@OneToMany(mappedBy = "event", cascade = CascadeType.ALL, orphanRemoval = true)
@JsonIgnoreProperties("event")
private Set<OptResult> results = new HashSet<>();
public OptEvent() {
}
现在我自己找到了答案。
public static Specification<Event> filterWithinRadius(double longitute, double latitude, double radius) {
return new Specification<Event>() {
@Override
public Predicate toPredicate(Root<Event> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
GeometryFactory factory = new GeometryFactory();
Point comparisonPoint = factory.createPoint(new Coordinate(latitude, longitute));
return SpatialPredicates.distanceWithin(builder, root.get("location"), comparisonPoint, radius);
}
};
}
重要的 SpatialPredicates 在 5.4.10 FINAL 版本中首次缺失,因此我不得不将依赖项带到 5.4.14 FINAL。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>5.4.14.Final</version>
</dependency>
如第一个问题中那样重建函数 1 到 1,以下结构是正确的。否则缺少从几何到地理的转换
public static Specification<Event> filterWithinRadius(double longitute, double latitude, double radius) {
return new Specification<Event>() {
@Override
public Predicate toPredicate(Root<Event> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
Expression<Geometry> geography = builder.function("geography", Geometry.class, root.get("location"));
Expression<Point> point = builder.function("ST_Point", Point.class, builder.literal(longitute),
builder.literal(latitude));
Expression<Point> comparisonPoint = builder.function("ST_SetSRID", Point.class, point,
builder.literal(4326));
Expression<Boolean> expression = builder.function(SpatialFunction.dwithin.toString(), boolean.class,
geography, comparisonPoint, builder.literal(radius));
return builder.equal(expression, true);
}
};
}
我想在 Predicate/Specification 中重写以下查询,以便我可以 link 它们。
此查询过滤我在特定区域内定义的所有 OptEvent 实体
@Query(value = "SELECT * FROM opt_event WHERE ST_DWithin(cast(opt_event.locationpoint as geography),ST_SetSRID(ST_Point(?2, ?1),4326), 100000);", nativeQuery = true)
public Set<OptEvent> findAllEventsInRange(double longitude, double latitude);
一般我都是这样写规范的,以后可以串起来。取决于是否应用过滤器。
public static Specification<OptEvent> filterArea(Double longitude, Double latitude) {
return new Specification<OptEvent>() {
@Override
public Predicate toPredicate(Root<OptEvent> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
SpatialRelateExpression geomExpression = SpatialRestrictions.within("locationpoint ", area);
//this is the only thing i could find, but i have no idea if its the right path or how i can transform it to the Specification
// what is area ?
//Example when i filter for the destination in the OptEvent
//return (root, query, builder) -> builder.like(builder.upper(root.get("destination")),
//"%" + destination.toUpperCase() + "%");
}
};
}
有关我的环境的更多信息。 我的 pom 下面。我使用 Postgres 和 Hibernate 5.4.10.Final.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
//Version 5.4.10 FINAL from Hibernate-Core
</dependency>
<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<version>1.13</version>
</dependency>
</dependencies>
对于我的定位点,我使用 org.locationtech.jts.geom.Point;
@Entity
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class OptEvent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String destination;
private String description;
private int year;
private EventSeries eventSeries;
private LocalDate eventDate;
@JsonSerialize(using = GeometrySerializer.class)
@JsonDeserialize(contentUsing = GeometryDeserializer.class)
private Point locationpoint;
@OneToMany(mappedBy = "event", cascade = CascadeType.ALL, orphanRemoval = true)
@JsonIgnoreProperties("event")
private Set<OptResult> results = new HashSet<>();
public OptEvent() {
}
现在我自己找到了答案。
public static Specification<Event> filterWithinRadius(double longitute, double latitude, double radius) {
return new Specification<Event>() {
@Override
public Predicate toPredicate(Root<Event> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
GeometryFactory factory = new GeometryFactory();
Point comparisonPoint = factory.createPoint(new Coordinate(latitude, longitute));
return SpatialPredicates.distanceWithin(builder, root.get("location"), comparisonPoint, radius);
}
};
}
重要的 SpatialPredicates 在 5.4.10 FINAL 版本中首次缺失,因此我不得不将依赖项带到 5.4.14 FINAL。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>5.4.14.Final</version>
</dependency>
如第一个问题中那样重建函数 1 到 1,以下结构是正确的。否则缺少从几何到地理的转换
public static Specification<Event> filterWithinRadius(double longitute, double latitude, double radius) {
return new Specification<Event>() {
@Override
public Predicate toPredicate(Root<Event> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
Expression<Geometry> geography = builder.function("geography", Geometry.class, root.get("location"));
Expression<Point> point = builder.function("ST_Point", Point.class, builder.literal(longitute),
builder.literal(latitude));
Expression<Point> comparisonPoint = builder.function("ST_SetSRID", Point.class, point,
builder.literal(4326));
Expression<Boolean> expression = builder.function(SpatialFunction.dwithin.toString(), boolean.class,
geography, comparisonPoint, builder.literal(radius));
return builder.equal(expression, true);
}
};
}