Micronaut jdbc 动态查询

问题描述

我正在尝试向我的查询添加动态过滤器。我已经检查过过滤器本身在语法上是否正确。

我的代码是:

@Repository
@JdbcRepository(dialect = Dialect.POSTGRES)
interface Roomrepository extends JpaRepository<Room,Long> {
    
    @Query(SELECT * FROM person pereson_ WHERE :filter)
    Page<Person> searchPerson(String filter,Pageable pageable)
}

我得到的错误

19:39:02.376 [default-nioEventLoopGroup-1-3] TRACE io.micronaut.data.query - Binding parameter at position 1 to value AND person_.name = 'bob' with data type: STRING
19:39:02.411 [default-nioEventLoopGroup-1-3] ERROR i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred: sql Error executing Query: ERROR: argument of WHERE must be type boolean,not type character varying
  Position: 158
io.micronaut.data.exceptions.DataAccessException: sql Error executing Query: ERROR: argument of WHERE must be type boolean,not type character varying

有什么想法吗?

解决方法

它不是那样工作的,顺便说一句,它的风格很糟糕,因为它让你很容易受到 sql 注入的影响。

首先创建一些过滤器类:

data class Filter( val name: String,val value: String)

您可以将过滤器分成多个存储库函数,并根据设置的过滤器从您的服务中调用它们

@Repository
@JdbcRepository(dialect = Dialect.POSTGRES)
interface PersonRepo : PageableRepository<Person,Long> {
     findByName(name: String,pageable: Pageable): Page<Person>
     findByNameAndAgeGreaterThanEquals(name: String,age: Int,pageable: Pageable): Page<Person>
     // add some more filter methods 
}

@Singleton
class PersonService(private val repo: PersonRepo) {

  fun searchPerson(filter: List<Filter>,pageable: Pageable) : Page<Person> {
     val filters = filter.map{it.name to it.value}.toMap()
     val isNamePresent = filters.containsKey("name")
     val isAgePresent = filter.containsKey("age")
     return if(isNamePresent && !isAgePresent) {
        repo.findByName(filters["name]!!.value,pageable)
     } else if(isNamePresent && isAgePresent) {
        repo.findByNameAndAgeGreaterThanEquals(filters["name]!!.value,filters["age]!!.value,pageable)
     } else {
         Page.empty()
     }
  }
}

或者你动态创建你的sql

@Repository
@JdbcRepository(dialect = Dialect.POSTGRES)
abstract class PersonRepo(private val jdbcOperations: JdbcOperations) : PageableRepository<Person,Long>{

    override fun searchPerson(filter: List<Filter>,pageable: Pageable): Page<Person> {

        val countSql= "SELECT COUNT(*) FROM person AS p ${filter.joinToString(" and ","WHERE "){it.name + "= ?"}}"
        val totalAmount = jdbcOperations.prepareStatement(sql) { statement ->
            filter.forEachIndexed { i,v -> statement.setString(i+1,v.value) }
            val resultSet = statement.executeQuery()
            jdbcOperations.entityStream(resultSet,Long::class.java).findFirst().orElseGet { 0}
        }

        val sql= "SELECT * FROM person AS p ${filter.joinToString(" and ","WHERE "){it.name + "= ?"}} SKIP ${pageable.offset} LIMIT {pageable.size}"
        val result = jdbcOperations.prepareStatement(sql) { statement ->
            filter.forEachIndexed { i,Person::class.java).toList()
        }
        return Page.of(result,pageable,totalAmount)
    }
}