我目前正在编写地理定位应用程序的代码(所以我使用 PostGIS)。我的查询当前按到用户的距离对结果进行排序,并且我想返回每个结果的距离(以米为单位)。
我的存储库代码如下所示(请注意,我正在执行键集分页,因此是 WHERE 条件):
@Query(value = "WITH distance_query AS (" +
" SELECT p.*, ST_Distance(p.location, ST_MakePoint(:lng, :lat)) AS distance_in_m " +
" FROM places p" +
") " +
"SELECT * FROM distance_query " +
"WHERE distance_in_m > :lastDistanceInM " +
"ORDER BY distance_in_m ASC", nativeQuery = true)
List<PlaceDto> findNearbyPlaces(
double lat,
double lng,
double lastDistanceInM
);
我的实体包含一个
@Transient
字段 Double distanceInM
,但查询中的 distance_in_m 未映射到该字段。我的理解是这是预期的,因为 @Transient
用于在映射时完全忽略带注释的字段。
我已经看到了使用
@Formula
的潜在方法,但由于 lat
和 lng
值是可变的,我认为这行不通。我还想避免重新计算距离(因此在我的原始查询中使用了 CTE)。
有什么方法可以让
distanceInM
字段填充计算值吗?
现在查询工作正常,唯一的问题是
distanceInM
属性未填充。
编辑:
PlaceDto
目前看起来像这样:
@Entity
@Table(name = "places")
public class PlaceDto {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String id;
private Date updateDate;
private String name;
public Point location;
private String address;
@Transient
public Double distanceInM;
public PlaceDto() {
}
// Getters
}
根据您的查询和实体类,下一种解决方案可以满足您的要求,并解决提取所有日期的问题。
首先:
创建一个与本机查询中的
AS
子句中的字段名称匹配的接口投影:
public interface PlaceDtoInterfaceProjection {
String getId();
Date getUpdateDate();
String getName();
Point getLocation();
String getAddress();
Double getDistanceInM();
}
第二个稍微改变一下存储库中的查询:
@Query(value = "WITH distance_query AS (" +
" SELECT p.id AS id, p.update_date AS updateDate, p.name AS name,"
+ " p.location AS location, p.address AS address,"
+ " ST_Distance(p.location, ST_MakePoint(:lng, :lat)) AS distanceInM " +
" FROM places p" +
") " +
"SELECT * FROM distance_query " +
"WHERE distanceInM > :lastDistanceInM " +
"ORDER BY distanceInM ASC", nativeQuery = true)
List<PlaceDtoInterfaceProjection> findNearbyPlaces(
@Param("lat") double lat,
@Param("lng") double lng,
@Param("lastDistanceInM") double lastDistanceInM
);
它会工作得很好,但我不太确定
Point
,顺便说一下,这是最简单的方法,更多细节或替代方法如何提取它,你可以找到spring-data-jpa-dto-native -查询