Introducció
Ktorm és un plugin del compilador:
compile "org.ktorm:ktorm-core:${ktorm.version}"
Schema
Enlloc de treballar directament amb SQL creem un objecte que representa una taula i que ens permet crear consultes directament amb Kotlin amb tots els beneficis que això comporta.
El primer que has de fer es crear un objecte per cada taula de la base de dades que vulguis accedir.
En la nostra base de dades de demostració tenim dos taules: department
i employee
:
object Departments : Table<Nothing>("department") {
val id = int("id").primaryKey()
val name = varchar("name")
val location = varchar("location")
}
object Employees : Table<Nothing>("employee") {
val id = int("id").primaryKey()
val name = varchar("name")
val job = varchar("job")
val managerId = int("manager_id")
val hireDate = date("hire_date")
val salary = long("salary")
val departmentId = int("department_id")
}
A continuació, ens conectem a la base de dades i fem una consulta senzilla:
fun main() {
val database = Database.connect("jdbc:mysql://localhost:3306/ktorm", user = "root", password = "***")
for (row in database.from(Employees).select()) {
println(row[Employees.name])
}
}
Quan executes aquest programa, Ktorm generarà una sentència SQL select * from employee
que és la que s'enviarà a la base de dades.
La funció select
torna un objecte que "overloads" l'operador d'iteració.
Per recòrrer l'iterador utlitzes un bucle for
imprimint el nom de cada treballador.
SQL DSL
Pots afegir algunes condicions de filtre a la consulta:
database
.from(Employees)
.select(Employees.name)
.where { (Employees.departmentId eq 1) and (Employees.name like "%vince%") }
.forEach { row ->
println(row[Employees.name])
}
Aquests és la sentència SQL que es genera:
select employee.name as employee_name
from employee
where (employee.department_id = ?) and (employee.name like ?)
Pots veure que el SQL que es genera correspon exactament al codi Kotlin que has escrit.
I més important, el compilador verifica que la consulta és correcta i l'IDE et pot ajudar a completar el codi.
També pots fer una consulta dinàmica, que aplica diferents condicions de filtre en diferents situacions:
val query = database
.from(Employees)
.select(Employees.name)
.whereWithConditions {
if (some_conditon) {
it += Employees.managerId.isNull()
}
if (una altraCondició) {
it += Empleats.departmentId eq 1
}
}
Agregació:
val t = Employees.aliased("t")
database
.from(t)
.select(t.departmentId, avg(t.salary))
.groupBy(t.departmentId)
.having { avg(t.salary) gt 100.0 }
.forEach { row ->
println("${row.getInt(1)}:${row.getDouble(2)}")
}
Joining
data class Names(val name: String?, val managerName: String?, val departmentName: String?)
val emp = Employees.aliased("emp")
val mgr = Employees.aliased("mgr")
val dept = Departments.aliased("dept")
val results = database
.from(emp)
.leftJoin(dept, on = emp.departmentId eq dept.id)
.leftJoin(mgr, on = emp.managerId eq mgr.id)
.select(emp.name, mgr.name, dept.name)
.orderBy(emp.id.asc())
.map { row ->
Names(
name = row[emp.name],
managerName = row[mgr.name],
departmentName = row[dept.name]
)
}
Insert:
database.insert(Employees) {
set(it.name, "jerry")
set(it.job, "trainee")
set(it.managerId, 1)
set(it.hireDate, LocalDate.now())
set(it.salary, 50)
set(it.departmentId, 1)
}
Update:
database.update(Employees) {
set(it.job, "engineer")
set(it.managerId, null)
set(it.salary, 100)
where {
it.id eq 2
}
}
Delete:
database.delete(Employees) { it.id eq 4 }
Entities & Column Binding
TODO