Entity
The super interface of all entity classes in Ktorm. This interface injects many useful functions into entities.
Ktorm requires us to define entity classes as interfaces extending from this interface. A simple example is given as follows:
interface Department : Entity<Department> {
val id: Int
var name: String
var location: String
}
Creating Entity Objects
As everyone knows, interfaces cannot be instantiated, so Ktorm provides a Entity.create function for us to create entity objects. This function will generate implementations for entity interfaces via JDK dynamic proxy and create their instances.
In case you don't like creating objects by Entity.create, Ktorm also provides an abstract factory class Entity.Factory. This class overloads the invoke
operator of Kotlin, so we just need to add a companion object to our entity class extending from Entity.Factory, then entity objects can be created just like there is a constructor: val department = Department()
.
Getting and Setting Properties
Entity objects in Ktorm are proxies, that's why Ktorm can intercept all the invocations on entities and listen the status changes of them. Behind those entity objects, there is a value table that holds all the values of the properties for each entity. Any operation of getting or setting a property is actually operating the underlying value table. However, what if the value doesn't exist while we are getting a property? Ktorm defines a set of rules for this situation:
If the value doesn't exist and the property’s type is nullable (e.g.
var name: String?
), then we’ll return null.If the value doesn't exist and the property’s type is not nullable (e.g.
var name: String
), then we can not return null anymore, because the null value here can cause an unexpected null pointer exception, we’ll return the type’s default value instead.
The default values of different types are well-defined:
For Boolean type, the default value is
false
.For Char type, the default value is
\u0000
.For number types (such as Int, Long, Double, etc.), the default value is zero.
For String type, the default value is an empty string.
For entity types, the default value is a new-created entity object which is empty.
For enum types, the default value is the first value of the enum, whose ordinal is 0.
For array types, the default value is a new-created empty array.
For collection types (such as Set, List, Map, etc.), the default value is a new created mutable collection of the concrete type.
For any other types, the default value is an instance created by its no-args constructor. If the constructor doesn't exist, an exception is thrown.
Moreover, there is a cache mechanism for default values, that ensures a property always returns the same default value instance even if it’s called twice or more. This can avoid some counterintuitive bugs.
Non-abstract members
If we are using domain driven design, then entities are not only data containers that hold property values, there are also some behaviors, so we need to add some business functions to our entities. Fortunately, Kotlin allows us to define non-abstract functions in interfaces, that’s why we don’t lose anything even if Ktorm’s entity classes are all interfaces. Here is an example:
interface Foo : Entity<Foo> {
companion object : Entity.Factory<Foo>()
val name: String
fun printName() {
println(name)
}
}
Then if we call Foo().printName()
, the value of the property name
will be printed.
Besides of non-abstract functions, Kotlin also allows us to define properties with custom getters or setters in interfaces. For example, in the following code, if we call Foo().upperName
, then the value of the name
property will be returned in upper case:
interface Foo : Entity<Foo> {
companion object : Entity.Factory<Foo>()
val name: String
val upperName get() = name.toUpperCase()
}
More details can be found in our website: https://www.ktorm.org/en/entities-and-column-binding.html#More-About-Entities
Serialization
The Entity interface extends from Serializable, so all entity objects are serializable by default. We can save them to our disks, or transfer them between systems through networks.
Note that Ktorm only saves entities’ property values when serialization, any other data that used to track entity status are lost (marked as transient). So we can not obtain an entity object from one system, then flush its changes into the database in another system.
Java uses ObjectOutputStream to serialize objects, and uses ObjectInputStream to deserialize them, you can refer to their documentation for more details.
Besides of JDK serialization, the ktorm-jackson module also supports serializing entities in JSON format. This module provides an extension for Jackson, the famous JSON framework in Java world. It supports serializing entity objects into JSON format and parsing JSONs as entity objects. More details can be found in its documentation.
Properties
Return the immutable view of this entity's changed properties and their original values.
Return this entity's KClass instance, which must be an interface.
Return the immutable view of this entity's all properties.
Functions
Clear the tracked property changes of this entity.
Indicate whether some other object is "equal to" this entity. Two entities are equal only if they have the same entityClass and properties.
Update the property changes of this entity into the database and return the affected record number.