我试图解决的问题是,使用用户提供的动态查询过滤表。需要描述问题的实体:
表格: run_events
柱: user_id, distance, time, speed, date, temperature, latitude, longitude
问题陈述是基于filterquery获取用户的run\u事件。查询的格式为,
((date = '2018-06-01') AND ((distance < 20) OR (distance > 10))
这个查询可以组合多个字段和多个and/or操作。
解决这个问题的一种方法是使用hibernate并将filterquery与您的查询连接起来。
"select * from run_events where user_id=:userId and "+filterQuery;
这需要您编写整个实现并使用会话,即。
String q = select * from run_events where user_id=:userId and "+filterQuery;
Query query = getSession().createQuery(q);
query.setParameter("userId", userId);
List<Object[]> result = query.list();
List<RunEvent> runEvents = new ArrayList<>();
for(Object[] obj: result){
RunEvent datum = new RunEvent();
int index = -1;
datum.setId((long) obj[++index]);
datum.setDate((Timestamp) obj[++index]);
datum.setDistance((Long) obj[++index]);
datum.setTime((Long) obj[++index]);
datum.setSpeed((Double) obj[++index]);
datum.setLatitude((Double) obj[++index]);
datum.setLongitude((Double) obj[++index]);
datum.setTemperature((Double) obj[++index]);
runEvents.add(datum);
}
这看起来不是很优雅,我想使用@query注解来实现这一点。
@Query(value = "select run_event from RunEvent where user_id = :userId and :query order by date asc")
List<RunEvent> getRunningData(@Param("userId") Long userId,
@Param("query") String query,
);
但这不起作用,因为在查询中不能以这种方式提供作为参数的查询。
有没有更好的、优雅的方法来使用jpa完成这个任务?
对于这种查询,使用规范和 predicate 似乎非常复杂。
3条答案
按热度按时间6g8kf2rb1#
回答一个简单的问题:这是不可能的
@Query
.在至少99%的情况下,这也是一个糟糕的设计决策,因为使用用户(或任何不受严格控制的源代码)提供的字符串通过字符串连接构造sql查询会使您面临sql注入攻击。
相反,您应该用某种api(criteria、querydsl、querybyexample)对查询进行编码,并使用它来创建查询。关于这个问题有很多问题和答案,所以我在这里不重复了。请参见带有任意and子句的动态spring数据jpa存储库查询示例
如果您坚持使用sql或jpql代码段作为输入,那么使用字符串连接的自定义实现就是一个不错的选择。
0sgqnhkj2#
这为sql注入打开了攻击。也许这就是为什么这个功能是不可能的。
通常,通过在末尾附加随机过滤器并运行它们来构造查询是个坏主意。
如果查询字符串做了一些尴尬的事情,比如
选择*from foo,其中id=1234或true;
从而返回所有行并给db带来沉重的负载,从而可能停止整个应用程序?
解决方案:您可以使用多个条件在jpa中动态过滤它,但是您需要自己解析querystring并添加必要的条件。
cnwbcb6i3#
您可以使用kolobok并忽略具有空值的字段。例如,创建一个类似于bellow的方法
并仅使用筛选器参数调用该方法,而其他参数为null