English | 简体中文

api-docs / me.liuwj.ktorm.entity / Entity

Entity

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

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 Entity.create functions for us to
create entity objects. Those functions generate implementations for entity interfaces via JDK dynamic proxy
and create their instances.

If you don’t like creating objects by Entity.create functions, 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 intercepts 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 (eg. var name: String?), then we’ll return null.
  • If the value doesn’t exist and the property’s type is not nullable (eg. 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 the String type, the default value is the 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://ktorm.liuwj.me/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 word. It supports serializing entity
objects into JSON format and parsing JSONs as entity objects. More details can be found in its documentation.

Types

NameSummary

Factory

abstract class Factory<E : Entity<E>> : TypeReference<E>

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

Properties

NameSummary

entityClass

abstract val entityClass: KClass<E>

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

properties

abstract val properties: Map<String, Any?>

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

Functions

NameSummary

copy

abstract fun copy(): E

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

delete

abstract fun delete(): Int

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

discardChanges

abstract fun discardChanges(): Unit

Clear the tracked property changes of this entity.

flushChanges

abstract fun flushChanges(): Int

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

get

abstract operator fun get(name: String): Any?

Obtain a property’s value by its name.

set

abstract operator fun set(name: String, value: Any?): Unit

Modify a property’s value by its name.

Companion Object Functions

NameSummary

create

fun create(entityClass: KClass<*>): Entity<*>

fun <E : Entity<E>> create(): E

Create an entity object by JDK dynamic proxy.