CRUD Operations
Stormify supports three styles for Create / Read / Update / Delete on entities. Pick whichever matches your language and taste — they all dispatch to the same underlying implementation and all honour an enclosing transaction { } block automatically.
The Three Styles
Pass entities to the Stormify (Kotlin) or StormifyJ (Java) instance directly.
The standard form — works everywhere without any setup.
Implement CRUDTable<T>, with the entity class itself as T, to expose
create(), update(), delete() as instance methods on the entity
itself; create() and update() return the entity, as stormify.create(user)
does. This is the idiomatic choice from Java where Kotlin extension
functions are not available.
public class User implements CRUDTable<User> {
@DbField(primaryKey = true) private int id;
private String name;
// Getters, setters...
}
// Register a default instance once at startup:
new StormifyJ(dataSource).asDefault();
User u = new User();
u.setName("Alice");
u = u.create(); // INSERT, returns the entity with its generated key
u.setName("Bob");
u.update(); // UPDATE
u.delete(); // DELETE
In Kotlin, any entity can call create(), update(), and delete()
directly — no interface needed. The query helpers (findById, findAll,
details) are also available at top level. Reloading an entity from the
database is done via stormify.refresh(entity) — there is no extension
refresh().
stormify.asDefault()
val user = User(name = "Alice").create() // INSERT, returns the created entity
user.name = "Bob"
user.update() // UPDATE
user.delete() // DELETE
val byId = findById<User>(42)
val active = findAll<User>("WHERE status = ?", "active")
val lines = order.details<OrderItem>() // Parent-child query
Transaction Participation
All three styles transparently join an enclosing transaction { } block — every
call on the same Stormify instance inside the block shares one connection and
rolls back together on exception. See Transactions for
details.
stormify.transaction {
stormify.create(User(name = "Alice")) // Direct style
User(name = "Bob").create() // Extension style
someEntity.update() // CRUDTable style
}
Batch CRUD Operations
Pass a collection to create, update, or delete to operate on many entities at once:
Generated keys in batch insert
When batch-inserting entities with auto-generated keys, the generated key is populated
back to the entity only if a single item is inserted. For batch inserts, use
database sequences (primarySequence) instead of auto-increment to ensure keys are
assigned before insertion.
Updating Only Changed Columns
By default update writes every updatable column of the entity. Set
dynamicUpdate on the instance to write only the columns that changed since the
entity was loaded:
- Which entities. Only entities that extend
StormifyEntity(and soAutoTable) keep the loaded values. Other entities, and entities that were never loaded whiledynamicUpdatewas on, get the fullUPDATE. After an update the written values become the reference for the next one. - Batches. A batch
updategroups the entities by the set of changed columns and runs one batched statement per group, on one connection. - Mutable values. The loaded values are copied, so a value changed in place
(a byte array, or a
java.util.DatethroughsetTime) counts as a change. - Cost. Each loaded entity keeps a second copy of its column values.
- Transactions. Inside
transaction { }the written values become the reference only on commit. When the transaction, or the savepoint of a nested one, rolls back, the entities it updated lose their reference and their next update writes every column, also whendynamicUpdatewas switched on inside the transaction. On a connection whose transaction is managed outside Stormify, the reference is not replaced, since the statement may still be rolled back there; the next update writes the changed columns again. - Primary key. An entity whose primary key changed gets the full
UPDATE. - Partial reads. The reference is taken from the object as loaded, not from the
row. A field that the
SELECTdid not read keeps its default value, and as long as it still equals that default it is not written. - No statement, no check. An entity with no changed column issues no statement, so nothing checks that its row still exists.