Backend API. Server-side code: this runs in a Codename One backend, not in the app on the device.

public final class Dao<T>

  1. Object
  2. Dao

Typed access to one entity’s table.

Reached through EntityManager.dao, never constructed: the statements it issues were generated from the entity at build time, and the instance is bound to the entity manager that supplies its connections.

Dao<Note> notes = em.dao(Note.class);
Note note = new Note();
note.title = "first";
notes.insert(note);              // note.id is now the generated key
List<Note> recent = notes.query()
        .eq("author", author)
        .orderBy("created", false)
        .limit(20)
        .list();

Each method takes a connection from the pool for exactly its own statement and gives it straight back, so a dao is safe to share between handlers and holds nothing between calls. Several statements that have to be one go through EntityManager.transaction, which pins one connection for the body.

Methods

public Class type()The entity class.
public String tableName()The table name, from @Entity(table) or the class’s simple name.
public void createTable() throws IOExceptionCREATE TABLE IF NOT EXISTS, in this engine’s spelling.
public void dropTable() throws IOExceptionDROP TABLE IF EXISTS.
public void insert(T entity) throws IOExceptionInserts entity.
public void resyncGeneratedKey() throws IOExceptionPuts the generated key back in step after rows were inserted with keys of their own.
public boolean update(T entity) throws IOExceptionUpdates every non-key column of the row whose key entity carries.
public boolean delete(T entity) throws IOExceptionDeletes the row whose key entity carries.
public boolean deleteById(Object id) throws IOExceptionDeletes the row with this key.
public T findById(Object id) throws IOExceptionThe row with this key, or null.
public List<T> findAll() throws IOExceptionEvery row.
public long count() throws IOExceptionHow many rows the table holds.
public Query<T> query()A query built from field names, which is the portable way to ask: the names are the entity’s Java fields and the builder quotes the columns they map to, so the same query runs on all three engines.
public List<T> find(String where, Object[] params) throws IOExceptionRows matching a WHERE clause written by hand, for the query the builder cannot express.
public T findOne(String where, Object[] params) throws IOExceptionThe first row matching a hand-written WHERE clause, or null.

Inherited methods

Method details

type

public Class type()
The entity class.

tableName

public String tableName()
The table name, from @Entity(table) or the class’s simple name.

createTable

public void createTable() throws IOException

CREATE TABLE IF NOT EXISTS, in this engine’s spelling.

This is a convenience for development and for tests, not a migration tool: it creates a table that is not there and does nothing at all to one that is, so a column added to the entity later does not appear. A schema that changes over time wants whatever the team runs migrations with.

dropTable

public void dropTable() throws IOException
DROP TABLE IF EXISTS.

insert

public void insert(T entity) throws IOException

Inserts entity.

When the key is the database’s to assign – @Id(autoIncrement = true), which is the default – the generated key is read back into the entity before this returns, on every engine. That is the operation the three disagree about most: PostgreSQL has no last-insert-id and answers through INSERT … RETURNING instead. See Database.insert.

resyncGeneratedKey

public void resyncGeneratedKey() throws IOException

Puts the generated key back in step after rows were inserted with keys of their own.

Supplying your own key is a supported thing – a data import, a test fixture, a restore – and on SQLite and MySQL doing it also moves the counter, so the next generated insert carries on above what is there. On PostgreSQL it does not: an explicit value leaves the identity’s sequence where it was, and the next generated insert reuses a key that already exists. MEASURED on a fresh table, explicit id 1 followed by a generated insert: SQLite and MySQL answer 2, PostgreSQL fails with “duplicate key value violates unique constraint”.

Call this once after an import. It is a no-op on the engines that need none, so the caller writes the same line whatever it is deployed against – which is the whole reason it is here rather than in every importer.

Nothing calls it for you: the ORM’s own insert never supplies a key for a generated column, so it cannot tell that an import happened.

update

public boolean update(T entity) throws IOException
Updates every non-key column of the row whose key entity carries.

Returns

whether a row matched. False is the answer a handler turns into a 404, and it is why this returns something where the client’s dao returns void: on a server the row that was not there is a case, not an impossibility.

delete

public boolean delete(T entity) throws IOException
Deletes the row whose key entity carries.

deleteById

public boolean deleteById(Object id) throws IOException
Deletes the row with this key.

findById

public T findById(Object id) throws IOException
The row with this key, or null.

findAll

public List<T> findAll() throws IOException
Every row.

count

public long count() throws IOException
How many rows the table holds.

query

public Query<T> query()
A query built from field names, which is the portable way to ask: the names are the entity’s Java fields and the builder quotes the columns they map to, so the same query runs on all three engines.

find

public List<T> find(String where, Object[] params) throws IOException

Rows matching a WHERE clause written by hand, for the query the builder cannot express.

where is appended after WHERE and its ? are bound from params. It is SQL, so what it names is COLUMNS rather than fields, and an unquoted name in it folds to lower case on PostgreSQL the way any unquoted name does – which is the portability the builder keeps and this gives up. Never build it by concatenating a value: that is the injection this whole surface exists to make unnecessary.

findOne

public T findOne(String where, Object[] params) throws IOException

The first row matching a hand-written WHERE clause, or null.

Asks the database for ONE row. Reading them all and keeping the first is the same answer and an unbounded amount of work to get it: a predicate that matches a large table materialised the whole of it, mapped every row into an entity, and then dropped all but one. Query.first has always done this; this is the hand-written half catching up.