Break Changes in Ktorm 3.0
After a few months, we finally ushered in another major version update of Ktorm (Ktorm 3.0). This update contains many optimizations, and there are also some incompatible changes, which is hereby explained.
If these incompatible updates have an impact on your project, we are very sorry, but this is a trade-off that must be made in order to ensure the long-term iteration of the framework. Please simply modify your code according to this document, which will only cost you a few minutes time.
ktorm-global
Ktorm 2.7 deprecated the global variable Database.global
and a series of APIs based on it, making users explicitly specify the Database
instances to use while performing database operations, instead of implicitly use Database.global
. For more information about the previous version, please refer to About Deprecating Database.global.
Using global variables is a bad design pattern. Code written in this way will be coupled with some global states, which is difficult to be tested and extended, and this is why we have to deprecate Database.global
. However, there are also some advantages, as we can make some APIs more concise with the help of the global variable. For example, Employees.findAll()
, after Ktorm 2.7, we have to write database.sequenceOf(Employees).toList()
, which looks a lot more verbose.
Ktorm 3.0 has completely removed Database.global
and its related APIs. But in order to give you more choices, we provide an additional module ktorm-global, which reimplements those deprecated APIs in version 2.7. You can use it as needed.
To use ktorm-global, you should add a Maven dependency first:
1 | <dependency> |
Or Gradle:
1 | compile "org.ktorm:ktorm-global:${ktorm.version}" |
Then connect to the database via function Database.connectGlobally
:
1 | Database.connectGlobally("jdbc:mysql://localhost:3306/ktorm", user = "root", password = "***") |
This function returns a new-created Database
object, you can define a variable to save the returned value if needed. But generally, it’s not necessary to do that, because ktorm-global will save the latest created Database
instance automatically, then obtain it via Database.global
when needed.
1 | Database.global.useConnection { conn -> |
With the help of the global object, our code can be more shorter, for example, create a query by directly using the extension function Table.select
:
1 | for (row in Employees.select()) { |
Use Table.findList
to obtain entity objects in the table that matches the given condition:
1 | val employees = Employees.findList { it.departmentId eq 1 } |
Use Table.sumBy
to sum a column in the table:
1 | val total = Employees.sumBy { it.salary } |
For more convenient usages, please explore by yourself. You can also refer to Changes in Ktorm 2.7. Almost all those deprecated functions are reimplemented in ktorm-global.
Use = Instead of Property Delegation to Define Columns
Before Ktorm 3.0, when we created a table object, we needed to use the by
keyword and define the columns as property delegates, like this:
1 | // Before Ktorm 3.0 |
But now, we no longer need property delegates anymore, just use the equal sign =
:
1 | // Ktorm 3.0 |
Using the equal sign =
is more simple and straightforward, and avoids some extra fields generated by the compiler for property delegates. However, this change will cause many compilation errors in your project after upgrading to the new version. Don’t worry, the only thing you need to do is just to find out all table objects in your project, and replace the by
keywords with equal signs =
in batches.
Query doesn’t Implement Iterable anymore
In the past, in order to easily obtain the query results, we decided to let Query
implement the Iterable
interface, so that we can iterate the results by a for-each loop, or process them via extension functions like map
, flatMap
, etc. For example:
1 | data class Emp(val id: Int?, val name: String?, val salary: Long?) |
But this also brings us a lot of problems, because the names of many extension functions of Iterable
are similar to the functions of Query
, and there may even be name conflicts, which will cause many misunderstandings for users, such as #124, #125.
Therefore, we decided that in Ktorm 3.0, Query
no longer implements the Iterable
interface anymore. And to keep our DSL code unchanged, we also provide some extension functions that are equivalent to those of Iterable
’s. After the upgrade, you will find that although some compilation errors may occur, your code is almost not needed to change. The only thing you may need is to add a line of import
statement to change the original calls to the Iterable.map
function to Query.map
:
1 | import org.ktorm.dsl.* |
Support Compound Primary Keys
A compound primary key is composed of multiple columns, which together uniquely identify a table row. In Ktorm 3.0, we also support configuring compound primary keys for tables. The usage is very simple, we just need to call the primaryKey
function for each column of the compound keys when creating table objects:
1 | object Departments : Table<Nothing>("t_department") { |
This is not just a simple enhancement feature, but there is also an incompatibility with previous versions. The val primaryKey: Column<*>
property in the BaseTable
class has been removed and changed to val primaryKeys: List<Column<*>>
, which is used to get all the columns that make up the primary key.
Others
In addition to the incompatible changes above, Ktorm 3.0 also contains many updates from enthusiasts in the open source community, thanks for their contributions:
- MySQL
bulkInsert
function supportson duplcate key update
. Thank @hangingman - PostgreSQL
hstore
data type and a series of operators for it. Thank @arustleund - ktorm-jackson supports simple Jackson annotations, like
@JsonProperty
,@JsonAlias
,@JsonIgnore
. Thank @onXoot