Рубрики
Без рубрики

Расширение хранилища данных Spring с помощью делегирования

Недавно я написал несколько постов о делегации Котлина. При этом я р… Помеченный kotlin, java, spring, spring data.

Недавно я написал несколько постов о делегации Котлина. При этом я понял полезный способ применить его к хранилищам данных Spring. Что позволило бы Spring Data продолжать разбрызгивать некоторую магию, предоставляя маршрут для настройки. Код, показанный в этом посте, написан на Kotlin, но по-прежнему имеет отношение к Java.

В этом сообщении используется R2DBC, но содержимое достаточно общее, чтобы быть применимым к любому модулю Spring Data.

Чтение Асинхронный доступ к СУБД с помощью Spring Data R2DBC и Делегирование классов в Kotlin было бы полезно здесь, если у вас мало базовых знаний в этих областях.

В качестве резюме. В чем заключается волшебство, которое предоставляет Spring Data?

Spring Data позволяет вам написать интерфейс, в котором от вас требуется только определять нужные вам запросы. Затем он выполнит всю работу по созданию реализации и внедрению зависимостей за вас. Это выглядит примерно так:

@Repository
interface PersonRepository : R2dbcRepository {

  @Query("SELECT * FROM people WHERE age > $1")
  fun findAllByAgeGreaterThan(age: Int): Flux
}

Поскольку используется Spring Data R2DBC, полностью выведенные запросы еще не полностью поддерживаются. Вот почему запрос записывается вручную.

Недостатком этого является то, что он создает реализацию на основе интерфейса. Поэтому, если вы хотите выполнить какую-либо настройку, вам нужно будет самостоятельно создать экземпляр интерфейса, внедрить его зависимости и реализовать каждый запрос. Например:

class PersonRepositoryImpl(
  private val entity: RelationalEntityInformation,
  private val databaseClient: DatabaseClient,
  converter: R2dbcConverter,
  private val accessStrategy: ReactiveDataAccessStrategy
) : SimpleR2dbcRepository(entity, databaseClient, converter, accessStrategy),
  PersonRepository {

  override fun findAllByAgeGreaterThan(age: Int): Flux {

    val mapper: StatementMapper.TypedStatementMapper =
      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  save(objectToSave: S): Mono {
    // 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 findAllByAgeGreaterThan(int age) {
    return delegate.findAllByAgeGreaterThan(age);
  }

  @Override
  public  Mono save(S entity) {
    // override `save` implementation
  }

  // all other implementations of `PersonRepository` functions
}

В обеих версиях Делегирование PersonRepository вызывает реализацию найти всех по возрасту, превышающему определенный в PersonRepository . До сих пор не было потрачено никаких усилий непосредственно на написание функции для запроса к базе данных.

Когда используется Делегирующий PersonRepository , все вызовы функций, которые не переопределены, будут делегированы реализации PersonRepository |/, созданной Spring.

Для кого-то вроде меня, кому на самом деле не нравится собирать SQL-запросы и писать весь код преобразования. Использование делегирования таким образом действительно позволяет вам использовать преимущества Spring Data, в то же время предоставляя вам возможность настраивать результат. Объем кода, который вы сохраняете, на самом деле может быть не таким уж большим. Но при этом значительно сокращаются усилия, необходимые для его объединения. Просто позвольте Весне сделать всю тяжелую работу за вас!

Если вам понравился этот пост или вы сочли его полезным (или и то, и другое), пожалуйста, не стесняйтесь подписываться на меня в Twitter по адресу @LankyDanDev и не забудьте поделиться с кем-либо еще, кто может счесть это полезным!

Оригинал: “https://dev.to/lankydandev/augmenting-a-spring-data-repository-through-delegation-5efp”