meadow-in-spring

我最近写了几篇关于科特林代表团的帖子。在此过程中,我认识到了将其应用于 Spring Data 存储库的有用方法。这将允许 Spring Data 继续洒一些魔法,同时提供自定义路由。

本文中显示的代码位于 Kotlin 中,但仍与 Java 相关。本文使用 R2DBC,但内容通用,可适用于任何弹簧数据模块。

如果您在这些领域没有太多背景知识,那么在 Kotlin 中使用 Spring Data R2DBC和类委派读取异步 RDBMS 访问将是有益的。

您可能还喜欢:使用弹簧数据 JPA

春季数据提供的魔力是什么?

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,可以消除创建此类的痛苦。然后,您可以添加所需的所有自定义项。

在科特林,这看起来像:

@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

发现所有年龄大人(年龄);
}

@Override
公共 <S 扩展人员> 单声道<S> 保存(S 实体) |
重写”保存”实现
}

“人员存储库”函数的所有其他实现
}

在这两个版本中,
DelegatingPersonRepository调用实现
findAllByAgeGreaterThan
PersonRepository .到目前为止,没有直接花费在编写函数来查询数据库上。

使用 DelegatingPersonRepository 时,未重写的所有函数调用都将委托给创建的 Spring 的 PersonRepository 实现。

对于像我这样的人,他并不真正喜欢将 SQL 查询和编写所有转换代码放在一起,以这种方式使用委派确实允许您利用Spring Data的优势,同时仍然为您提供自定义结果的空间。您保存的代码量实际上可能并不大。但是,需要作出相当大的努力,以将其放在一起。就让春天为你做所有的重担吧!

如果你喜欢这个帖子或发现它有帮助(或两者兼而有之),那么请随时在Twitter上关注我,@LankyDanDev,并记住与任何人谁可能会发现这很有用!

进一步阅读

Comments are closed.