Interface EntityAgent

All Superinterfaces:
AutoCloseable, EntityHandler

public interface EntityAgent extends EntityHandler
Provides entity operations that are performed independently of a persistence context. This interface enables more direct control over interaction with the database than what is possible with EntityManager.

An instance of EntityAgent must be obtained from an EntityManagerFactory and is only able to manage persistence of entities belonging to the associated persistence unit. In the Jakarta EE environment, an entity agent with a lifecycle managed by the container may be obtained by dependency injection.

  • An EntityAgent obtained directly from an EntityManagerFactory is never thread safe, and it is always wrong to share a reference to such an entity agent between multiple concurrently executing threads.
  • On the other hand, in the Jakarta EE container environment, a reference to a container-managed, transaction-scoped entity agent obtained by injection is safe to invoke concurrently from distinct threads. The container redirects invocations to distinct instances of EntityAgent based on transaction affinity.

An application-managed EntityAgent may be created via a call to EntityManagerFactory.createEntityAgent(EntityAgent.CreationOption...). The EntityAgent must be explicitly closed via a call to EntityHandler.close() to allow resources to be cleaned up by the persistence provider. This approach places almost complete responsibility for cleanup and exception management on the client, and is thus considered quite error-prone. It is much safer to use the methods EntityManagerFactory.runInTransaction(Class, Consumer) and EntityManagerFactory.callInTransaction(Class, Function).

entityManagerFactory.runInTransaction(EntityAgent.class, entityAgent -> {
    // do work
    ...
});

In the Jakarta EE environment, a container-managed EntityAgent may be obtained by dependency injection, using PersistenceAgent.

// inject the container-managed entity agent
@PersistenceAgent(unitName="orderMgt")
EntityAgent entityAgent;

If the persistence unit has resource local transaction management, transactions must be managed using the EntityTransaction obtained by calling EntityHandler.getTransaction().

A complete idiom for custom application management of the EntityAgent and its associated resource-local EntityTransaction is as follows:

EntityAgent entityAgent = entityManagerFactory.createEntityAgent();
EntityTransaction transaction = entityAgent.getTransaction();
try {
    transaction.begin();
    // do work
    ...
    transaction.commit();
}
catch (Exception e) {
    if (transaction.isActive()) transaction.rollback();
    throw e;
}
finally {
    entityAgent.close();
}

An EntityAgent has no associated persistence context, and works only with detached entity instances. When a method of this interface is called, any necessary interaction with the database happens immediately and synchronously. In particular, update is an explicit operation. Since there is no flush operation, and since the entities themselves are detached, modifications to the entities are never automatically detected and made persistent.

An exception thrown by a method of an EntityAgent, or by a method of an instance of Query obtained from an EntityAgent, is considered recoverable and does not usually cause the active transaction to be marked for rollback.

Since:
4.0
See Also:
  • Method Details

    • insert

      void insert(@Nonnull Object entity)
      Insert a record.

      If the entity Id field is declared to be generated, for example, if it is annotated GeneratedValue, the id is generated and assigned to the given instance.

      • The PreInsert callback is triggered.
      • The PostInsert callback is triggered if the operation is successful.
      Parameters:
      entity - a new or removed entity instance
      Throws:
      IllegalArgumentException - if the given instance is determined to not be new or removed
      EntityExistsException - if any kind of uniqueness constraint is violated
      PersistenceException - if a record could not be inserted in the database
    • insertMultiple

      void insertMultiple(@Nonnull List<?> entities)
      Insert every record in the given list. The records are inserted in the order in which they occur in the given list and according to the requirements of the insert(Object) method.
      Parameters:
      entities - The entities to be inserted.
      Throws:
      IllegalArgumentException - if one of the given instances is determined to not be new or removed
      EntityExistsException - if any kind of uniqueness constraint is violated
      PersistenceException - if a record could not be inserted in the database
      See Also:
    • update

      void update(@Nonnull Object entity)
      Update a record.

      • The PreUpdate callback is triggered.
      • The PostUpdate callback is triggered if the operation is successful.
      Parameters:
      entity - a detached entity instance
      Throws:
      IllegalArgumentException - if the given instance is determined to not be detached
      OptimisticLockException - if an optimistic locking conflict is detected, that is, if no row matching the identifier of the given entity exists in the database or if an optimistic version check fails
      PersistenceException - if a record could not be updated in the database
    • updateMultiple

      void updateMultiple(@Nonnull List<?> entities)
      Update every record in the given list. The records are updated in the order in which they occur in the given list and according to the requirements of the update(Object) method.
      Parameters:
      entities - The entities to be updated.
      Throws:
      IllegalArgumentException - if the one of the given instances is determined to not be detached
      OptimisticLockException - if an optimistic locking conflict is detected, that is, if no row matching the identifier of one of the given entities exists in the database or if an optimistic version check fails
      PersistenceException - if a record could not be updated in the database
      See Also:
    • delete

      void delete(@Nonnull Object entity)
      Delete a record.

      • The PreDelete callback is triggered.
      • The PostDelete callback is triggered if the operation is successful.
      Parameters:
      entity - a detached entity instance
      Throws:
      IllegalArgumentException - if the given instance is determined to not be detached
      OptimisticLockException - if an optimistic locking conflict is detected, that is, if no row matching the identifier of the given entity exists in the database or if an optimistic version check fails
      PersistenceException - if a record could not be deleted from the database
    • deleteMultiple

      void deleteMultiple(@Nonnull List<?> entities)
      Delete every record in the given list. The records are deleted in the order in which they occur in the given list and according to the requirements of the delete(Object) method.
      Parameters:
      entities - The entities to be deleted.
      Throws:
      IllegalArgumentException - if the one of the given instances is determined to not be detached
      OptimisticLockException - if an optimistic locking conflict is detected, that is, if no row matching the identifier of one of the given entities exists in the database or if an optimistic version check fails
      PersistenceException - if a record could not be deleted from the database
      See Also:
    • upsert

      void upsert(@Nonnull Object entity)
      Perform an upsert, that is, insert the record if it does not exist, or update it if it already exists.

      This method never performs id generation and does not accept an entity instance with a null identifier. When id generation is required, use insert(Object).

      On the other hand, upsert() does accept an entity instance with an assigned identifier value, even if the entity Id field is declared to be generated, for example, if it is annotated GeneratedValue. Thus, this method may be used to import data from an external source.

      • The PreUpsert callback is triggered.
      • The PostUpsert callback is triggered if the operation is successful.
      Parameters:
      entity - a detached entity instance, or a new instance with an assigned identifier
      Throws:
      IllegalArgumentException - if the given entity has a null identifier value
      OptimisticLockException - if an optimistic locking conflict is detected, that is, if an optimistic version check fails
      PersistenceException - if a record could not be upserted in the database
    • upsertMultiple

      void upsertMultiple(@Nonnull List<?> entities)
      Upsert every record in the given list. The records are upserted in the order in which they occur in the given list and according to the requirements of the upsert(Object) method.
      Parameters:
      entities - The entities to be inserted or updated.
      Throws:
      IllegalArgumentException - if one of the given entities has a null identifier value
      OptimisticLockException - if an optimistic locking conflict is detected, that is, if an optimistic version check fails
      PersistenceException - if a record could not be upserted in the database
      See Also:
    • refresh

      void refresh(@Nonnull Object entity)
      Refresh the entity instance state from the database.
      Parameters:
      entity - The entity to be refreshed.
      Throws:
      EntityNotFoundException - if the given entity no longer exists in the database
      PersistenceException - if a record could not be read from the database
    • refreshMultiple

      void refreshMultiple(@Nonnull List<?> entities)
      Refresh multiple entities.
      Parameters:
      entities - The entities to be refreshed.
      Throws:
      EntityNotFoundException - if one of the given entities no longer exists in the database
      PersistenceException - if a record could not be read from the database
      See Also:
    • refresh

      void refresh(@Nonnull Object entity, @Nonnull LockModeType lockMode)
      Refresh the entity instance state from the database.
      Parameters:
      entity - The entity to be refreshed.
      lockMode - The LockMode to be applied.
      Throws:
      EntityNotFoundException - if the given entity no longer exists in the database
      PersistenceException - if a record could not be read from the database
    • fetch

      <T> T fetch(T association)
      Fetch an association or collection that was configured for lazy loading if it has not yet been fetched from the database. If the association or collection is already fetched, this operation has no effect. For convenience, this method always returns its argument.
      Book book = agent.get(Book.class, isbn);  // book is immediately detached
      agent.fetch(book.getAuthors())            // fetch the associated authors
           .forEach(author -> ... );            // iterate the collection
      
      Type Parameters:
      T - The type of the entity attribute type, either an entity type or a collection type
      Parameters:
      association - A lazy association
      Returns:
      The association with its state fetched.
      Throws:
      PersistenceException - if a record could not be read from the database
    • addOption

      void addOption(@Nonnull EntityAgent.Option option)
      Specify an option controlling the behavior of this entity agent, overwriting any existing option of the same type.
      Parameters:
      option - the option
    • getOptions

      @Nonnull Set<EntityAgent.Option> getOptions()
      Get the options controlling the behavior of this entity agent. The returned set includes options set via addOption(EntityAgent.Option), along with options specified via EntityHandler.setCacheRetrieveMode(CacheRetrieveMode) or EntityHandler.setCacheStoreMode(CacheStoreMode). Mutation of the returned set does not affect the options of the entity agent.
      Returns:
      the options for this entity agent