Define Entities as Any Kind of Classes
In Ktorm 2.5, we did a refactoring of the code. This refactoring allowed us defining entities as any kind of classes, such as data class, POJO, and so on. From then on, the entity classes in Ktorm do not have to be defined as interfaces extending from Entity
anymore. This reduces the invasion of user code to some extent, which is very important for a common-used library.
About how to define entities as interfaces, see the documentation of Entities & Column Binding.
Table & BaseTable
Before the refactoring, Table
was the common base class of all table objects in Ktorm, providing basic abilities of table definition, column definition, and binding support to Entity
interfaces. But now, there is a more fundamental base class BaseTable
on top of Table
.
BaseTable
is an abstract class. It is the common base class of all table objects after Ktorm 2.5. It provides the basic ability of table and column definition but doesn’t support any binding mechanisms. There is an abstract function doCreateEntity
in BaseTable
. Subclasses should implement this function, creating an entity object from the result set returned by a query, using the binding rules defined by themselves. Here, the type of the entity object could be an interface extending from Entity
, or a data class, POJO, or any kind of classes.
Just like before, Table
limits our entity classes with an upper bound Entity
on the type parameter. It provides the basic ability of table and column definition as it’s a subclass of BaseTable
, and it also supports a binding mechanism with Entity
interfaces based on functions such as bindTo
, references
. Additionally, Table
implements the doCreateEntity
function from the parent class. This function automatically creates an entity object using the binding configuration specified by bindTo
and references
, reading columns’ values from the result set and filling them into corresponding entity properties.
Use Data Class
To use data classes, we should define our table objects as subclasses of BaseTable
instead of Table
. Also, it’s not needed to call bindTo
and references
anymore because BaseTable
doesn’t support any binding mechanisms. Instead, we implement the doCreateEntity
function, creating an entity object from the result set manually by ourselves.
Here is an example:
1 | data class Staff( |
As you can see, the Staff
here is just a simple data class. Ktorm doesn’t have any special requirements for this class. It is no longer necessary to define it as an interface, which minimizes the intrusion of the framework to user code. The table object Staffs
is also defined as a subclass of BaseTable
and implements the doCreateEntity
function, in which we get columns’ values via square brackets []
and fill them into the data object.
Technically, it is OK for us to end this article here, because the usages (such as SQL DSL, Sequence APIs, etc) are totally the same as before. Here are some simple examples.
Query data via SQL DSL:
1 | val staffs = database |
Obtain entity objects via sequence APIs, and sorting them by the specific column:
1 | val staffs = database.staffs |
Get the number of staffs with a salary of less than 100 thousand in each department:
1 | val counts = database.staffs |
For more usages, see the documentation of SQL DSL and Entity Sequence.
Limitation
However, data classes are not perfect, and that’s why Ktorm decided to use Entity
interfaces when it was originally designed. In fact, even after Ktorm 2.5 released, defining entities as interfaces is still our first choice because there are currently two limitations to using data classes:
- Column bindings are not available: Since
BaseTable
is directly used as the parent class, we cannot configure the bindings between database columns and entity properties viabindTo
andreferences
while defining our table objects. Therefore, each table object must implement thedoCreateEntity
function, in which we should create our entity objects manually. - Entity manipulation APIs are not available: Since we define entities as data classes, Ktorm cannot proxy them and cannot detect the status changes of entity objects, which makes it impossible for us to use entity manipulation APIs such as
sequence.add(..)
,entity.flushChanges()
, etc. But SQL DSL is not affected. We can still use DSL function such asdatabase.insert(..) {..}
anddatabase.update(..) {..}
to perform our data modifications.
Because of these limitations, you should think carefully before you decide to define your entities as data classes. You might be benefited from using data classes and you would lose other things at the same time. Remember: Defining entities as interfaces is still our first choice.