kotlinintermediate

Spring Data with Kotlin Repository Patterns

Use Spring Data JPA with Kotlin: entity mapping, custom queries, projections, and specifications.

kotlin
import jakarta.persistence.*
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import java.time.LocalDateTime

@Entity
@Table(name = "products")
data class Product(
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,
    val name: String,
    val description: String = "",
    val price: Double,
    val category: String,
    val inStock: Boolean = true,
    val createdAt: LocalDateTime = LocalDateTime.now()
)

interface ProductRepository : JpaRepository<Product, Long> {
    fun findByCategory(category: String): List<Product>
    fun findByPriceBetween(min: Double, max: Double): List<Product>
    fun findByNameContainingIgnoreCase(name: String, pageable: Pageable): Page<Product>
    fun findByInStockTrue(): List<Product>
    fun countByCategory(category: String): Long
    fun existsByName(name: String): Boolean

    @Query("SELECT p FROM Product p WHERE p.category = :category AND p.price <= :maxPrice")
    fun findAffordable(category: String, maxPrice: Double): List<Product>

    @Query(
        value = "SELECT category, COUNT(*) as cnt, AVG(price) as avg_price FROM products GROUP BY category",
        nativeQuery = true
    )
    fun getCategoryStats(): List<Array<Any>>

    @Query("SELECT p.name as name, p.price as price FROM Product p WHERE p.category = :category")
    fun findNameAndPrice(category: String): List<ProductSummary>
}

interface ProductSummary {
    val name: String
    val price: Double
}

import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class ProductService(private val repo: ProductRepository) {
    fun search(query: String, page: Pageable) =
        repo.findByNameContainingIgnoreCase(query, page)

    @Transactional
    fun updatePrice(id: Long, newPrice: Double): Product {
        val product = repo.findById(id)
            .orElseThrow { NoSuchElementException("Product $id not found") }
        return repo.save(product.copy(price = newPrice))
    }
}

Sponsored

Supabase

Use Cases

  • Database access with Spring Data JPA in Kotlin
  • Custom query methods and projections
  • Paginated search with derived queries

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.