Class EntityManager

java.lang.Object
com.codename1.backend.orm.EntityManager

public final class EntityManager extends Object

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.

  • Method Details

    • register

      public static void register(EntityDefinition definition)
      Installs a generated definition. The generated bootstrap calls this.
    • registered

      public static EntityDefinition[] registered()
      Every registered definition, in registration order.
    • open

      public static EntityManager open(DataSource pool) throws IOException
      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

      public static EntityManager open(Database db) throws IOException
      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

      public <T> Dao<T> dao(Class<T> entity)

      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

      public Session 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

      public void createTables() throws IOException

      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

      public Object transaction(EntityManager.Work body) throws Exception

      Runs body inside 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

      public DataSource dataSource()
      The pool behind this manager, or null when it is pinned to one connection.
    • database

      public Database database()
      The connection this manager is pinned to, or null when it holds a pool.
    • dialect

      public Dialect dialect()
      How this manager's engine spells things. See 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 Database does 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.