我最近写了几篇有关Kotlin代表团的文章。 通过这样做,我实现了一种将其应用于Spring Data存储库的有用方法。 这将使Spring Data在提供定制路线的同时继续散布一些魔力。 这篇文章中显示的代码在Kotlin中,但仍然与Java有关。
这篇文章使用R2DBC,但是内容足够通用,可以应用于任何Spring Data模块。
如果您在这些领域没有太多的背景知识,那么在Kotlin中 使用Spring Data R2DBC和类委托读取异步RDBMS访问将是有益的。
作为回顾。 Spring Data提供的魔力是什么?
Spring Data允许您编写一个仅需要定义所需查询的接口。 然后它将完成创建实现和为您注入依赖项的所有工作。 看起来像这样:
@Repository interface PersonRepository : R2dbcRepository<Person, Int> { @Query ( "SELECT * FROM people WHERE age > $1" ) fun findAllByAgeGreaterThan(age: Int): Flux<Person> }
由于正在使用Spring Data R2DBC,因此尚不完全支持完全推断的查询。 这就是为什么手动写出查询的原因。
不利的一面是它正在基于接口创建实现。 因此,如果要进行任何类型的自定义,则需要自己创建接口的实例,注入其依赖关系并实现每个查询。 例如:
class PersonRepositoryImpl( private val entity: RelationalEntityInformation<Person, Int>, private val databaseClient: DatabaseClient, converter: R2dbcConverter, private val accessStrategy: ReactiveDataAccessStrategy ) : SimpleR2dbcRepository<Person, Int>(entity, databaseClient, converter, accessStrategy), PersonRepository { override fun findAllByAgeGreaterThan(age: Int): Flux<Person> { val mapper: StatementMapper.TypedStatementMapper<Person> = accessStrategy.statementMapper.forType(entity.javaType) val selectSpec: StatementMapper.SelectSpec = mapper .createSelect(entity.tableName) .withProjection(accessStrategy.getAllColumns(entity.javaType)) .withCriteria(Criteria.where( "age" ).greaterThan(age)) val operation: PreparedOperation<*> = mapper.getMappedObject(selectSpec) return databaseClient.execute().sql(operation).`as`(entity.javaType).fetch().all() } }
是的,该查询代码可能很糟糕,我相信您可以做得更好。 你明白我的意思。
可以通过委派基于您的接口实现的Spring仓库来消除创建此类的麻烦。 然后,您可以添加所需的所有自定义。
在Kotlin中,这看起来像:
@Repository class DelegatingPersonRepository( private val delegate: PersonRepository) : PersonRepository by delegate { override fun <S : Person> save(objectToSave: S): Mono<S> { // override `save` implementation } // any other overrides (kotlin provides delegated implementations) }
在Java中,这比较麻烦,但仍然可以轻松实现:
@Repository public class DelegatingPersonRepository implements PersonRepository { private final PersonRepository delegate; public DelegatingPersonRepository(PersonRepository delegate) { this .delegate = delegate; } @Override public Flux<Person> findAllByAgeGreaterThan( int age) { return delegate.findAllByAgeGreaterThan(age); } @Override public <S extends Person> Mono<S> save(S entity) { // override `save` implementation } // all other implementations of `PersonRepository` functions }
在这两个版本中, DelegatingPersonRepository
调用PersonRepository
定义的findAllByAgeGreaterThan
的实现。 到目前为止,还没有直接花费精力来编写查询数据库的功能。
使用DelegatingPersonRepository
,所有未覆盖的函数调用将委托给Spring创建的PersonRepository
的实现。
对于像我这样的人,他真的不喜欢将SQL查询放在一起并编写所有转换代码。 通过这种方式使用委派确实可以使您充分利用Spring Data的优势,同时仍然为您提供自定义结果的空间。 您节省的代码量实际上可能不是那么大。 但是,将其组合在一起所需的工作量大大减少了。 让Spring为您完成所有繁重的工作!
翻译自: https://www.javacodegeeks.com/2019/09/augmenting-spring-data-repository-delegation.html