Class EntityManager
The entry point to the build-time ORM: entities in, daos out.
EntityManager em = EntityManager.open(dataSource);
Dao<Note> notes = em.dao(Note.class);
The conventions are the client's, deliberately. An entity is a class with
@Entity, @Id, @Column and @DbTransient on it;
the build reads those out of the compiled class and writes the dao; the dao
issues prepared statements and never reflects. What differs on this side is
what it issues them THROUGH: Database, so the
same entity class is stored in the app's SQLite file and in the server's
PostgreSQL, and only the connection knows which.
How a dao gets here
Nothing looks a class up by name. The build writes one
<Entity>Cn1BackendDao per entity and a
cn1app.BackendDaoBootstrap whose constructor registers every one of
them, and the generated server entry point runs that before it starts
listening.
That entry point is the ONLY thing that can run it. The bootstrap is
generated during process-classes, after javac has compiled the module's own
sources, so a main written by hand cannot name it -- a module that
sets its own mainClass reaches the database through DataSource and not
through this.
The names are not the client's -- there the dao is <Entity>Cn1Dao
and the bootstrap is cn1app.DaoBootstrap -- because an entity shared
between an application and its server has BOTH generated for it, and the two
have to be able to sit on one classpath.
That indirection is not ceremony. The translator drops a class nothing
references, and obfuscation renames the ones that survive, so a registry
populated by scanning or by Class.forName would be empty in exactly the
builds that ship. A generated class holding a direct reference to each dao is
what keeps them alive, and the registry is keyed on Class.getName(),
which registration and lookup agree about within one execution however the
names were rewritten.
An entity manager takes its snapshot of the registry when it is opened, so everything is resolved once at start-up and a request never contends on a map.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interfaceA unit of work run insidetransaction(EntityManager.Work). -
Method Summary
Modifier and TypeMethodDescriptionvoidclose()Closes the pool, or the connection, this manager was opened over.voidCreates the table of every registered entity that has none.<T> Dao<T> The dao for an entity class.database()The connection this manager is pinned to, or null when it holds a pool.The pool behind this manager, or null when it is pinned to one connection.dialect()How this manager's engine spells things.static EntityManagerAn entity manager over one connection.static EntityManageropen(DataSource pool) An entity manager over a pool, which is the usual form: each operation borrows a connection for its own statement and gives it straight back.Opens an independent managed persistence context.static voidregister(EntityDefinition definition) Installs a generated definition.static EntityDefinition[]Every registered definition, in registration order.Runsbodyinside one transaction on one connection.
-
Method Details
-
register
Installs a generated definition. The generated bootstrap calls this. -
registered
Every registered definition, in registration order. -
open
An entity manager over a pool, which is the usual form: each operation borrows a connection for its own statement and gives it straight back.- Throws:
IOException
-
open
An entity manager over one connection. Everything it does is serialized on that connection, which is what a single-connection SQLite server wants and what a server engine under load does not.- Throws:
IOException
-
dao
The dao for an entity class.
Resolved from the snapshot taken when this manager was opened, so it allocates nothing and cannot fail for a class that was registered before then. A class that was not registered says so, because the cause is nearly always one of two things: the annotation is missing, or the generated bootstrap was never run.
-
openSession
Opens an independent managed persistence context. The caller must close it. Begin and complete each transaction on the same thread; other users of its connection wait until commit, rollback, or session close. Closing never commits.- Returns:
- a new persistence context with independent managed entity state
- Throws:
IllegalStateException- if called on a transaction-scoped manager
-
createTables
Creates the table of every registered entity that has none.
For development and for tests. Production schemas are migrations, and this creates a table without ever altering one, so it cannot be that.
- Throws:
IOException
-
transaction
Runs
bodyinside one transaction on one connection.The entity manager the body is handed is pinned to that connection, so every dao reached through it is inside the transaction. A dao taken from the OUTER manager is not -- that borrows a second connection, which the database sees as another session.
An entity manager that is already pinned joins the transaction it is in rather than opening another: all three engines refuse a nested BEGIN, and a service method that works alone should not break when another one calls it.
- Throws:
Exception
-
dataSource
The pool behind this manager, or null when it is pinned to one connection. -
database
The connection this manager is pinned to, or null when it holds a pool. -
dialect
-
close
public void close()Closes the pool, or the connection, this manager was opened over.
The manager handed to a transaction body owns nothing and closes nothing: the connection under it belongs to the transaction, which is not over. One opened over a caller's
Databasedoes close it, which is what the sentence above promises and what the client-side entity manager does -- leaving it open made repeated open/use/close cycles leak a SQLite handle or a network session each time.
-