SlideShare a Scribd company logo
Alternatives of JPA
CatalogTribe in Shanghai
debop@coupang.com 2018.01.16
Agenda
• What is ORM
• Pros / Cons of JPA
• Current status in Coupang
• Alternatives of JPA
• Slick
• jOOQ
• Exposed
• Requery
ORM (Object Relational Mapping)
• OOP’s object graph vs Relational Database
• Focus OOP, not Relational Database
• No matter of RDBMS vendor - Same code
• Hibernate coverage is 95% over traditional SQL statements
• ORM not suitable for data centric application in performance
• Why should you use an ORM?
Pros of JPA
• Focus to Java Object graph & OOP
• No need to know relations and constraints of entities
• No need to know specific DB features by various vendor
• No need to know SQL, just use Java API
• Supplement by HQL or JPQL or QueryDSL
• All support for Stateful, Stateless (Default is Stateful)
Cons of JPA
• If you knew SQL already, JPA is wired
• Hard to learning (exponential)
• Low performance by stateful and fetch by id
• No suitable for Bulk or Set operations
• Massive Insert, Statistical Summary (Cube …)
• Non-Threadsafe Session - Low throughput
• Need to learn specific JPAVendor (Hibernate, Eclipse Link)
• HQL, @DynamicInsert, @LazyCollection
• 2nd Cache (recommend JCache (JSR-305))
Current Status in Coupang
• No Deep Dive
• Missing override (hashCode, equals, toString)
• No using @NatualId
• Bad Policy / Bad Design
• Every entity has Own identifier (Some case no need)
• Poor performance -> Mislead “JPA is bad”
• Apply not suitable case
• Bulk operations, Statistical operations
• No use supplement features
• StatelessSession, 2nd Cache …
Features in Alternatives of JPA
• Design Principle
• OOP based, Support Multi DBVendor
• No need stateful for Reference object
• Support association, inheritance, converter in JPA
• Performance
• Speed up like Plain SQL
• Stateless
• Support Asynchronous or Reactive
• Support Bulk or Batch operations
Slick
ORM for Scala
Slick
• Database access library
• Not ORM -> Functional Relational Mapping
• Bring relational model to Scala OOP
• Natural fit ( no impedance mismatch)
• Stateless
• Matures (Slick version 3) (Non-blocking DBIO)
• Essential Slick Book
Slick - schema definition
Entity
Schema
Definition
Slick - Query
// Get Users with age > 20
Query statement
Async
Operations
Slick - DML
Slick -Transactions
Define Repository
Async
Execution with
Transaction
Slick - Plain SQL
ResultSet to
Tuple
ResultSet to
Entity
jOOQ
Java Object Oriented Query
jOOQ
• Reflect Database Schema to generate Entity Class
• Typesfe SQL (akaTypesafe MyBatis)
• Database First (Not ORM)
• Stateless
• Need DBMS Owner Authority
• jOOQ vs Hibernate :When to choose which
jOOQ - Generate Codes
jOOQ - typesafe SQL
SELECT * FROM BOOK
WHERE BOOK.PUBLISHED_IN = 2011
ORDER BY BOOK.TITLE
create.selectFrom(BOOK)
.where(BOOK.PUBLISHED_IN.eq(2011))
.orderBy(BOOK.TITLE)
select().from(t).where(t.a.eq(select(t2.x).from(t2));
// Type-check here: ---------------> ^^^^
select().from(t).where(t.a.eq(any(select(t2.x).from(t2)));
// Type-check here: -------------------> ^^^^
select().from(t).where(t.a.in(select(t2.x).from(t2));
// Type-check here: ---------------> ^^^^
select(t1.a).from(t1).unionAll(select(t2.a).from(t2));
// Type-check here: ----------------> ^^^^
select(t1.a, t1.b).from(t1).union(select(t2.a, t2.b).from(t2));
// Type-check here: -------------------> ^^^^^^^^^^
Predicates
Set operations
requery
ORM for Java & Kotlin & Android
requery
• No reflection (apt code generation) - Fast instancing
• Fast startup & performance
• Schema generation
• Blocking / Non-blocking API (Reactive with RxJava)
• Support partial object / refresh / upsert
• Custom type converter like JPA
• Compile time entity validation
• Support almost JPA annotations
@Entity
abstract class AbstractPerson { 
    @Key @Generated int id; 
   
    @Index("name_index") // table specification 
    String name;     
   
    @OneToMany // relationships 1:1, 1:many, many to many   
    Set<Phone> phoneNumbers;
   
    @Converter(EmailToStringConverter.class)
    Email email;
    @PostLoad // lifecycle callbacks
    void afterLoad() { updatePeopleList(); }
    // getter, setters, equals & hashCode automatically generated into Person.java 
}
requery - define entity
Identifier
Entity class
Converter
Listeners
Result<Person> query = data
    .select(Person.class)
    .where(Person.NAME.lower().like("b%"))
    .and(Person.AGE.gt(20))
    .orderBy(Person.AGE.desc())
    .limit(5)
    .get();
Observable<Person> observable = data
    .select(Person.class)
    .orderBy(Person.AGE.desc())
    .get()
    .observable();
requery - query
Query by Fluent API
Reactive Programming
Cold Observable
Non blocking
@Entity(model = "tree")

interface TreeNode {

    @get:Key

    @get:Generated

    val id: Long
   
    @get:Column

    var name: String



    @get:ManyToOne(cascade = [DELETE])
    var parent: TreeNode?



    @get:OneToMany(mappedBy = "parent", cascade = [SAVE, DELETE])

    val children: MutableSet<TreeNode>
}
requery - self refence by Kotlin
Identifier
Entity class
1:N, N:1
Cascade
requery - Blob/Clob usage
class ByteArrayBlobConverter : Converter<ByteArray, Blob> {
override fun getPersistedSize(): Int? = null
override fun getPersistedType(): Class<Blob> = Blob::class.java
override fun getMappedType(): Class<ByteArray> = ByteArray::class.java
override fun convertToMapped(type: Class<out ByteArray>?, value: Blob?): ByteArray? {
return value?.binaryStream?.readBytes()
}
override fun convertToPersisted(value: ByteArray?): Blob? {
return value?.let { SerialBlob(it) }
}
}
requery - Blob property
@Entity(model = "kt")
interface BigModel {
@get:Key
@get:Generated
@get:Column(name = "model_id")
val id: Int
@get:Column(name = "model_name")
var name: String?
@get:Convert(value = ByteArrayBlobConverter::class)
@get:Column(name = "model_picture")
var picture: ByteArray?
}
Blob column
Exposed
Kotlin SQL Framework
Exposed - Kotlin SQL Framework
• Lightweight SQL Library
• Provide two layers of data access
• Typesafe SQL wrapping DSL
• Lightweight Data Access Object
• See : First steps with Kotlin/Exposed
• Cons
• Not support parameterized SQL
Exposed - SQL DSL
object Users : Table() {
    val id = varchar("id", 10).primaryKey() // Column<String> 
    val name = varchar("name", length = 50) // Column<String>
    val cityId = (integer("city_id") references Cities.id).nullable() // Column<Int?>
}
object Cities : Table() { 
    val id = integer("id").autoIncrement().primaryKey() // Column<Int>
    val name = varchar("name", 50) // Column<String> 
}
Exposed - SQL DSL
val munichId = Cities.insert {
    it[name] = "Munich"
} get Cities.id 
Cities.insert { it[name] = "Prague" } 
Users.insert { 
    it[id] = "andrey" 
    it[name] = "Andrey" 
    it[cityId] = saintPetersburgId 
}
Users.insert { 
    it[id] = "sergey"
    it[name] = "Sergey" 
    it[cityId] = munichId
}
Exposed - SQL DSL - Join
(Users innerJoin Cities)
    .slice(Users.name, Cities.name)
    .select {
        (Users.id.eq("andrey") or Users.name.eq("Sergey")) and
        Users.id.eq("sergey") and Users.cityId.eq(Cities.id)
    }
    .forEach { 
        println("${it[Users.name]} lives in ${it[Cities.name]}")
    }
Exposed - SQL DSL - Join 2
((Cities innerJoin Users)
    .slice(Cities.name, Users.id.count())
    .selectAll()
    .groupBy(Cities.name))
    .forEach {
        val cityName = it[Cities.name]
        val userCount = it[Users.id.count()]
        if (userCount > 0) {
            println("$userCount user(s) live(s) in $cityName")
        } else { 
            println("Nobody lives in $cityName")
        }
     }
Exposed - DAO
object Users : IntIdTable() {
    val name = varchar("name", 50).index()
    val city = reference("city", Cities)
    val age = integer("age")
}
object Cities: IntIdTable() { 
    val name = varchar("name", 50)
}
Schema Definition
class User(id: EntityID<Int>) : IntEntity(id){
    companion object : IntEntityClass<User>(Users)
    var name by Users.name
    var city by City referencedOn Users.city
    var age by Users.age 
}
class City(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<City>(Cities)
    var name by Cities.name
    val users by User referrersOn Users.city 
}
Entity Definition
Exposed - DAO Usage
val munich = City.new {
    name = "Munich"
}
User.new {
    name = "a"
    city = munich
    age = 5
}
User.new {
    name = "b"
    city = munich
    age = 27
}
munich.users.joinToString { it.name }
User.find { Users.age.between(18, 60) }
OneTo Many
All user’s name in Munich
Conclusion
• Already legacy database exists ? Use only Java
• jOOQ or requery
• Scala only ? -> Slick
• Kotlin only ? -> requery, Exposed
• No matter language? -> requery
• Need Reactive programming? ->
• requery with kotlinx-requery
• kotlinx-rxjava2-jdbc ( we will open March )
Thank you!

More Related Content

PDF
Spring data requery
PDF
Requery overview
PDF
JUnit5 and TestContainers
PDF
Kotlin @ Coupang Backed - JetBrains Day seoul 2018
PDF
Kotlin @ Coupang Backend 2017
PPTX
Kotlin coroutines and spring framework
PPT
55 New Features in Java 7
PDF
Scala @ TechMeetup Edinburgh
Spring data requery
Requery overview
JUnit5 and TestContainers
Kotlin @ Coupang Backed - JetBrains Day seoul 2018
Kotlin @ Coupang Backend 2017
Kotlin coroutines and spring framework
55 New Features in Java 7
Scala @ TechMeetup Edinburgh

What's hot (20)

PDF
Scala coated JVM
PPTX
BASTA 2013: Custom OData Provider
PDF
Scala at HUJI PL Seminar 2008
PPT
Scala introduction
PDF
Kotlin talk
PPTX
Scale up your thinking
PPTX
Demystifying Oak Search
PPTX
Kotlin is charming; The reasons Java engineers should start Kotlin.
ODP
Slickdemo
PPTX
All about scala
KEY
Clojure Intro
PDF
"Migrate large gwt applications - Lessons Learned" By Harald Pehl
PDF
Kotlin: Why Do You Care?
PPTX
Akka Actor presentation
PDF
#살아있다 #자프링외길12년차 #코프링2개월생존기
DOCX
Advance Java Programs skeleton
PDF
Scala active record
PDF
Kotlin Developer Starter in Android projects
PPTX
Building a Unified Data Pipline in Spark / Apache Sparkを用いたBig Dataパイプラインの統一
PDF
Scala ActiveRecord
Scala coated JVM
BASTA 2013: Custom OData Provider
Scala at HUJI PL Seminar 2008
Scala introduction
Kotlin talk
Scale up your thinking
Demystifying Oak Search
Kotlin is charming; The reasons Java engineers should start Kotlin.
Slickdemo
All about scala
Clojure Intro
"Migrate large gwt applications - Lessons Learned" By Harald Pehl
Kotlin: Why Do You Care?
Akka Actor presentation
#살아있다 #자프링외길12년차 #코프링2개월생존기
Advance Java Programs skeleton
Scala active record
Kotlin Developer Starter in Android projects
Building a Unified Data Pipline in Spark / Apache Sparkを用いたBig Dataパイプラインの統一
Scala ActiveRecord
Ad

Similar to Alternatives of JPA/Hibernate (20)

PDF
Naver_alternative_to_jpa
PDF
Java e i database: da JDBC a JPA
PPT
YDP_API&MS_UNIT_hiii detail notes to understand api.ppt
PPT
YDP_API&MS_UNIT_IIIii8iiiiiiiii8iiii.ppt
PDF
Introduction to JPA and Hibernate including examples
PDF
運用 Exposed 管理及操作資料庫
PPTX
Module-3 for career and JFSD ppt for study.pptx
PDF
ActiveJDBC - ActiveRecord implementation in Java
ODP
Working with jpa
PPTX
SeaJUG May 2012 mybatis
ODP
Polyglot persistence with Spring Data
PDF
Using the latest Java Persistence API 2 Features - Tech Days 2010 India
PDF
An Introduction to Spring Data
PPT
Persisting Your Objects In The Database World @ AlphaCSP Professional OSS Con...
PDF
Data access 2.0? Please welcome: Spring Data!
PDF
Using Scala Slick at FortyTwo
PDF
JPoint'15 Mom, I so wish Hibernate for my NoSQL database...
PDF
An introduction into Spring Data
PDF
Spring Boot Tutorial Part 2 (JPA&Hibernate) .pdf
PDF
Evolution of database access technologies in Java-based software projects
Naver_alternative_to_jpa
Java e i database: da JDBC a JPA
YDP_API&MS_UNIT_hiii detail notes to understand api.ppt
YDP_API&MS_UNIT_IIIii8iiiiiiiii8iiii.ppt
Introduction to JPA and Hibernate including examples
運用 Exposed 管理及操作資料庫
Module-3 for career and JFSD ppt for study.pptx
ActiveJDBC - ActiveRecord implementation in Java
Working with jpa
SeaJUG May 2012 mybatis
Polyglot persistence with Spring Data
Using the latest Java Persistence API 2 Features - Tech Days 2010 India
An Introduction to Spring Data
Persisting Your Objects In The Database World @ AlphaCSP Professional OSS Con...
Data access 2.0? Please welcome: Spring Data!
Using Scala Slick at FortyTwo
JPoint'15 Mom, I so wish Hibernate for my NoSQL database...
An introduction into Spring Data
Spring Boot Tutorial Part 2 (JPA&Hibernate) .pdf
Evolution of database access technologies in Java-based software projects
Ad

More from Sunghyouk Bae (10)

PDF
Introduction of failsafe
PDF
measure metrics
PPTX
Java naming strategy (자바 명명 전략)
PPTX
테스트자동화와 TDD
PPTX
SpringBoot with MyBatis, Flyway, QueryDSL
PPTX
JUnit & AssertJ
PPTX
좋은 개발자 되기
PDF
Using AdoRepository
PDF
Multithread pattern 소개
PDF
Strategy Maps
Introduction of failsafe
measure metrics
Java naming strategy (자바 명명 전략)
테스트자동화와 TDD
SpringBoot with MyBatis, Flyway, QueryDSL
JUnit & AssertJ
좋은 개발자 되기
Using AdoRepository
Multithread pattern 소개
Strategy Maps

Recently uploaded (20)

PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PPTX
CHAPTER 2 - PM Management and IT Context
PPTX
Essential Infomation Tech presentation.pptx
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PPTX
L1 - Introduction to python Backend.pptx
PPTX
Reimagine Home Health with the Power of Agentic AI​
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
AI in Product Development-omnex systems
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PPTX
Transform Your Business with a Software ERP System
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
Which alternative to Crystal Reports is best for small or large businesses.pdf
CHAPTER 2 - PM Management and IT Context
Essential Infomation Tech presentation.pptx
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Softaken Excel to vCard Converter Software.pdf
Navsoft: AI-Powered Business Solutions & Custom Software Development
Adobe Illustrator 28.6 Crack My Vision of Vector Design
2025 Textile ERP Trends: SAP, Odoo & Oracle
L1 - Introduction to python Backend.pptx
Reimagine Home Health with the Power of Agentic AI​
wealthsignaloriginal-com-DS-text-... (1).pdf
How Creative Agencies Leverage Project Management Software.pdf
How to Choose the Right IT Partner for Your Business in Malaysia
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
AI in Product Development-omnex systems
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Transform Your Business with a Software ERP System

Alternatives of JPA/Hibernate

  • 2. Agenda • What is ORM • Pros / Cons of JPA • Current status in Coupang • Alternatives of JPA • Slick • jOOQ • Exposed • Requery
  • 3. ORM (Object Relational Mapping) • OOP’s object graph vs Relational Database • Focus OOP, not Relational Database • No matter of RDBMS vendor - Same code • Hibernate coverage is 95% over traditional SQL statements • ORM not suitable for data centric application in performance • Why should you use an ORM?
  • 4. Pros of JPA • Focus to Java Object graph & OOP • No need to know relations and constraints of entities • No need to know specific DB features by various vendor • No need to know SQL, just use Java API • Supplement by HQL or JPQL or QueryDSL • All support for Stateful, Stateless (Default is Stateful)
  • 5. Cons of JPA • If you knew SQL already, JPA is wired • Hard to learning (exponential) • Low performance by stateful and fetch by id • No suitable for Bulk or Set operations • Massive Insert, Statistical Summary (Cube …) • Non-Threadsafe Session - Low throughput • Need to learn specific JPAVendor (Hibernate, Eclipse Link) • HQL, @DynamicInsert, @LazyCollection • 2nd Cache (recommend JCache (JSR-305))
  • 6. Current Status in Coupang • No Deep Dive • Missing override (hashCode, equals, toString) • No using @NatualId • Bad Policy / Bad Design • Every entity has Own identifier (Some case no need) • Poor performance -> Mislead “JPA is bad” • Apply not suitable case • Bulk operations, Statistical operations • No use supplement features • StatelessSession, 2nd Cache …
  • 7. Features in Alternatives of JPA • Design Principle • OOP based, Support Multi DBVendor • No need stateful for Reference object • Support association, inheritance, converter in JPA • Performance • Speed up like Plain SQL • Stateless • Support Asynchronous or Reactive • Support Bulk or Batch operations
  • 9. Slick • Database access library • Not ORM -> Functional Relational Mapping • Bring relational model to Scala OOP • Natural fit ( no impedance mismatch) • Stateless • Matures (Slick version 3) (Non-blocking DBIO) • Essential Slick Book
  • 10. Slick - schema definition Entity Schema Definition
  • 11. Slick - Query // Get Users with age > 20 Query statement Async Operations
  • 14. Slick - Plain SQL ResultSet to Tuple ResultSet to Entity
  • 16. jOOQ • Reflect Database Schema to generate Entity Class • Typesfe SQL (akaTypesafe MyBatis) • Database First (Not ORM) • Stateless • Need DBMS Owner Authority • jOOQ vs Hibernate :When to choose which
  • 18. jOOQ - typesafe SQL SELECT * FROM BOOK WHERE BOOK.PUBLISHED_IN = 2011 ORDER BY BOOK.TITLE create.selectFrom(BOOK) .where(BOOK.PUBLISHED_IN.eq(2011)) .orderBy(BOOK.TITLE) select().from(t).where(t.a.eq(select(t2.x).from(t2)); // Type-check here: ---------------> ^^^^ select().from(t).where(t.a.eq(any(select(t2.x).from(t2))); // Type-check here: -------------------> ^^^^ select().from(t).where(t.a.in(select(t2.x).from(t2)); // Type-check here: ---------------> ^^^^ select(t1.a).from(t1).unionAll(select(t2.a).from(t2)); // Type-check here: ----------------> ^^^^ select(t1.a, t1.b).from(t1).union(select(t2.a, t2.b).from(t2)); // Type-check here: -------------------> ^^^^^^^^^^ Predicates Set operations
  • 19. requery ORM for Java & Kotlin & Android
  • 20. requery • No reflection (apt code generation) - Fast instancing • Fast startup & performance • Schema generation • Blocking / Non-blocking API (Reactive with RxJava) • Support partial object / refresh / upsert • Custom type converter like JPA • Compile time entity validation • Support almost JPA annotations
  • 21. @Entity abstract class AbstractPerson {      @Key @Generated int id;          @Index("name_index") // table specification      String name;              @OneToMany // relationships 1:1, 1:many, many to many        Set<Phone> phoneNumbers;         @Converter(EmailToStringConverter.class)     Email email;     @PostLoad // lifecycle callbacks     void afterLoad() { updatePeopleList(); }     // getter, setters, equals & hashCode automatically generated into Person.java  } requery - define entity Identifier Entity class Converter Listeners
  • 22. Result<Person> query = data     .select(Person.class)     .where(Person.NAME.lower().like("b%"))     .and(Person.AGE.gt(20))     .orderBy(Person.AGE.desc())     .limit(5)     .get(); Observable<Person> observable = data     .select(Person.class)     .orderBy(Person.AGE.desc())     .get()     .observable(); requery - query Query by Fluent API Reactive Programming Cold Observable Non blocking
  • 23. @Entity(model = "tree")
 interface TreeNode {
     @get:Key
     @get:Generated
     val id: Long         @get:Column
     var name: String
 
     @get:ManyToOne(cascade = [DELETE])     var parent: TreeNode?
 
     @get:OneToMany(mappedBy = "parent", cascade = [SAVE, DELETE])
     val children: MutableSet<TreeNode> } requery - self refence by Kotlin Identifier Entity class 1:N, N:1 Cascade
  • 24. requery - Blob/Clob usage class ByteArrayBlobConverter : Converter<ByteArray, Blob> { override fun getPersistedSize(): Int? = null override fun getPersistedType(): Class<Blob> = Blob::class.java override fun getMappedType(): Class<ByteArray> = ByteArray::class.java override fun convertToMapped(type: Class<out ByteArray>?, value: Blob?): ByteArray? { return value?.binaryStream?.readBytes() } override fun convertToPersisted(value: ByteArray?): Blob? { return value?.let { SerialBlob(it) } } }
  • 25. requery - Blob property @Entity(model = "kt") interface BigModel { @get:Key @get:Generated @get:Column(name = "model_id") val id: Int @get:Column(name = "model_name") var name: String? @get:Convert(value = ByteArrayBlobConverter::class) @get:Column(name = "model_picture") var picture: ByteArray? } Blob column
  • 27. Exposed - Kotlin SQL Framework • Lightweight SQL Library • Provide two layers of data access • Typesafe SQL wrapping DSL • Lightweight Data Access Object • See : First steps with Kotlin/Exposed • Cons • Not support parameterized SQL
  • 28. Exposed - SQL DSL object Users : Table() {     val id = varchar("id", 10).primaryKey() // Column<String>      val name = varchar("name", length = 50) // Column<String>     val cityId = (integer("city_id") references Cities.id).nullable() // Column<Int?> } object Cities : Table() {      val id = integer("id").autoIncrement().primaryKey() // Column<Int>     val name = varchar("name", 50) // Column<String>  }
  • 29. Exposed - SQL DSL val munichId = Cities.insert {     it[name] = "Munich" } get Cities.id  Cities.insert { it[name] = "Prague" }  Users.insert {      it[id] = "andrey"      it[name] = "Andrey"      it[cityId] = saintPetersburgId  } Users.insert {      it[id] = "sergey"     it[name] = "Sergey"      it[cityId] = munichId }
  • 30. Exposed - SQL DSL - Join (Users innerJoin Cities)     .slice(Users.name, Cities.name)     .select {         (Users.id.eq("andrey") or Users.name.eq("Sergey")) and         Users.id.eq("sergey") and Users.cityId.eq(Cities.id)     }     .forEach {          println("${it[Users.name]} lives in ${it[Cities.name]}")     }
  • 31. Exposed - SQL DSL - Join 2 ((Cities innerJoin Users)     .slice(Cities.name, Users.id.count())     .selectAll()     .groupBy(Cities.name))     .forEach {         val cityName = it[Cities.name]         val userCount = it[Users.id.count()]         if (userCount > 0) {             println("$userCount user(s) live(s) in $cityName")         } else {              println("Nobody lives in $cityName")         }      }
  • 32. Exposed - DAO object Users : IntIdTable() {     val name = varchar("name", 50).index()     val city = reference("city", Cities)     val age = integer("age") } object Cities: IntIdTable() {      val name = varchar("name", 50) } Schema Definition class User(id: EntityID<Int>) : IntEntity(id){     companion object : IntEntityClass<User>(Users)     var name by Users.name     var city by City referencedOn Users.city     var age by Users.age  } class City(id: EntityID<Int>) : IntEntity(id) {     companion object : IntEntityClass<City>(Cities)     var name by Cities.name     val users by User referrersOn Users.city  } Entity Definition
  • 33. Exposed - DAO Usage val munich = City.new {     name = "Munich" } User.new {     name = "a"     city = munich     age = 5 } User.new {     name = "b"     city = munich     age = 27 } munich.users.joinToString { it.name } User.find { Users.age.between(18, 60) } OneTo Many All user’s name in Munich
  • 34. Conclusion • Already legacy database exists ? Use only Java • jOOQ or requery • Scala only ? -> Slick • Kotlin only ? -> requery, Exposed • No matter language? -> requery • Need Reactive programming? -> • requery with kotlinx-requery • kotlinx-rxjava2-jdbc ( we will open March )