Котлинский шаблон для использования Spring Data JPA «запрос по примеру»

Spring Data JPA представляет интересную функцию «запрос по примеру» (QBE) . Вы выражаете критерии поиска, создавая экземпляр объекта .

Вам не нужно писать JPQL. Он использует меньше «магии», чем делает вывод запроса репозитория . Синтаксис хорош. Это предотвращает взрывы тривиального кода репозитория. Он очень хорошо выживает в рефакторе.

Однако есть проблема: QBE работает только в том случае, если вы можете частично построить объект.

Вот моя сущность:

@Entity @Table(name="product") data class Product( @Id val id: String, val city: String, val shopName: String, val productName: String, val productVersion: Short ) 

Вот мой репозиторий (пустая! Это хорошая вещь о QBE):

 @Repository interface ProductRepository : JpaRepository<Product, String> 

И вот, как вы получите List<Product> – все продукты, которые продаются в каком-то магазине, в каком-то городе:

 productRepository.findAll(Example.of(Product(city = "London", shopName="OkayTea"))) 

Или, по крайней мере, это то, что я хочу сделать. Есть проблема. Невозможно построить этот объект:

 Product(city = "London", shopName="OkayTea") 

Это связано с тем, что конструктор Product требует, чтобы все его поля были определены. И действительно: это то, что я хочу большую часть времени.

Обычным компромиссом в Java было бы: создавать объекты, использующие конструктор no-args, делать все изменчивым, не иметь никаких гарантий относительно завершенности.

Есть ли хороший шаблон Котлин для решения этой проблемы:

  • обычно требуют, чтобы все аргументы были созданы при построении
  • также предоставляет некоторый механизм для создания частично сконструированных экземпляров для использования с примером API

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

Например: может быть, мы можем сделать объект mock / proxy, который, как представляется, является Продуктом, но не имеет тех же ограничений конструкции?

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

 @Entity @Table(name = "product") data class Product( @Id val id: String? = null, val city: String? = null, val shopName: String? = null, val productName: String? = null, val productVersion: Short? = null ) 

Однако вы должны управлять свойствами Product с помощью безопасного вызова ?. , например:

 val product = Product() // safe-call ---v val cityToLowerCase = product.city?.toLowerCase()