Entity

interface Entity<E : Entity<E>> : Serializable(source)

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.

Types

Link copied to clipboard
object Companion

Companion object provides functions to create entity instances.

Link copied to clipboard
abstract class Factory<E : Entity<E>> : TypeReference<E>

Abstract factory used to create entity objects, typically declared as companion objects of entity classes.

Properties

Link copied to clipboard
abstract val changedProperties: Map<String, Any?>

Return the immutable view of this entity's changed properties and their original values.

Link copied to clipboard
abstract val entityClass: KClass<E>

Return this entity's KClass instance, which must be an interface.

Link copied to clipboard
abstract val properties: Map<String, Any?>

Return the immutable view of this entity's all properties.

Functions

Link copied to clipboard
abstract fun copy(): E

Return a deep copy of this entity, which has the same property values and tracked statuses.

Link copied to clipboard
abstract fun delete(): Int

Delete this entity in the database and return the affected record number.

Link copied to clipboard
abstract fun discardChanges()

Clear the tracked property changes of this entity.

Link copied to clipboard
abstract operator override fun equals(other: Any?): Boolean

Indicate whether some other object is "equal to" this entity. Two entities are equal only if they have the same entityClass and properties.

Link copied to clipboard
abstract fun flushChanges(): Int

Update the property changes of this entity into the database and return the affected record number.

Link copied to clipboard
abstract operator fun get(name: String): Any?

Obtain a property's value by its name.

Link copied to clipboard
abstract override fun hashCode(): Int

Return a hash code value for this entity.

Link copied to clipboard
abstract operator fun set(name: String, value: Any?)

Modify a property's value by its name.

Link copied to clipboard
abstract override fun toString(): String

Return a string representation of this entity. The format is like Employee(id=1, name=Eric, job=contributor, hireDate=2021-05-05, salary=50).