Backend API. Server-side code: this runs in a Codename One backend, not in the app on the device.
public final class Dao<T>
- Object
- 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
Inherited methods
Method details
type
public Class type()tableName
public String tableName()createTable
public void createTable()
throws IOExceptionCREATE 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.
Throws
dropTable
public void dropTable()
throws IOExceptionThrows
insert
public void insert(T entity)
throws IOExceptionInserts 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.
Throws
resyncGeneratedKey
public void resyncGeneratedKey()
throws IOExceptionPuts 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.
Throws
update
public boolean update(T entity)
throws IOExceptionentity carries.Returns
Throws
delete
public boolean delete(T entity)
throws IOExceptionentity carries.Throws
deleteById
public boolean deleteById(Object id)
throws IOExceptionThrows
findById
public T findById(Object id)
throws IOExceptionThrows
findAll
public List<T> findAll()
throws IOExceptionThrows
count
public long count()
throws IOExceptionThrows
query
public Query<T> query()find
public List<T> find(String where, Object[] params)
throws IOExceptionRows 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.
Throws
findOne
public T findOne(String where, Object[] params)
throws IOExceptionThe 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.