- Java EE 8 and Angular
- Prashant Padmanabhan
- 982字
- 2021-07-02 19:22:36
Performing CRUD operations with entities
The basic usage of an EntityManager is to execute the create, read, update, and delete (CRUD) operations for the entity. These operations are performed using a transaction, and JPA supports two kinds:
- JTA container managed transactions: Demarcation of transactions are handled by the container, such as using a method with a transaction required attribute as part of a stateless bean. On completion of the method, the transaction will be committed.
- Resource local transactions: Demarcation of transactions must be done programmatically. For example, using the EntityTransaction instance and invoking its begin and commit operations.
Methods with read-only operations need not be performed within a transaction, although in a JEE environment there is hardly any overhead for a transaction with modern day containers. It's still best to measure this for your use case and decide.
Once you have an EntityManager obtained, as described in the text, It all starts with an EntityManager, then we can start performing the CRUD operations using it.
Creating an entity within the database is done using the persist operation on an EntityManager, which creates a record in the table for the entity. This operation is performed only on new entities which have no entry in the database.
In its simplest form, a persist operation can be done like so:
Task theTask = new Task(100L, "Work on next big thing");
em.persist(theTask);
The persist method inserts the non-managed entity into the database by firing an INSERT statement. Once the entity is persisted, it enters a managed state and thus any changes made to the entity within a transaction are tracked and updated in the database during the commit. If the entity being persisted has an embedded annotation reference to an embeddable class, then fields of that class are persisted as well. For example, a User having a composition relation with the Credential class, as shown before.
Updating an entity is done by simply performing field changes on a managed entity within a transaction and posting the transaction commits. The changes are automatically synchronized with the database. The transaction can be container managed using the EJB method within transactional bounds, or user managed, as shown here:
em.getTransaction().begin();
Task theTask = em.find(Task.class, 4L);
theTask.setAssignedon(LocalDate.of(2018, 7, 21));
em.getTransaction().commit();
It would be a mistake to follow this strategy to conditionally perform persist for a managed entity, as shown next:
@Stateless
public class TaskService {
@Inject EntityManager em;
public void update() {
Task task = em.find(Task.class, 2L); // Get existing task
task.setName("updated name here");
if( some condition ) {
em.persist(task); //Line won't make a difference
}
}
}
Here, the changed name of the task, will be synced to database irrespective of whether em.persist call is executed or not. For updating a managed entity, it's not required to call the persist method, as the entity will be saved as part of the transaction completion.
When working with detached entities, a merge operation is performed first, to synchronize the changes done to the entity in its detached state.
Removing an entity is done by using the remove method of EntityManager. This is done by first finding the entity, putting it into the managed state, then invoking the remove operation. A detached entity (which is a non-managed entity) cannot be passed to remove, and if passed it will throw an exception:
em.getTransaction().begin();
em.remove(theTask); // theTask is a reference to Task object
em.getTransaction().commit();
Reading an entity is very common and there are a variety of options available to perform a read operation, such as using the APIs or using JPQL, which is the query language for Java persistence. JPQL is similar to SQL but instead of working on tables and their columns, it works on the entities and their associations. We already looked at one example a little earlier when we used TypedQuery to find an entity by referencing a named query. Here's a similar snippet using createQuery:
TypedQuery<Task> query = em.createQuery("SELECT t FROM Task t", Task.class);
List<Task> tasks = query.getResultList();
The preceding code can be further expanded to restrict the data being fetched, such as in the case of fetching a paginated list of records. For such use cases, the Query/TypedQuery provides methods for result restrictions:
query.setFirstResult(start); //: Result would be fetched from the offset of the start number.
query.setMaxResults(pageSize); //: Results can be less or the same as the pageSize number.
If you don't need the flexibility of writing a query and need to just find an entity by its primary key, then the same can be done using the find method with EntityManager:
Task task = em.find(Task.class, 100L);
With JPA 2.2, there's now support for getting a Stream<X> from the result set. Both javax.persistence and TypedQuery / Query support the getResultStream method. This returns a Stream instance. An example usage is shown here:
TypedQuery<Task> query = em.createQuery("SELECT t from Task t",
Task.class);
List<String> names = query.getResultStream().map(Task::getName)
.collect(Collectors.toList());
It's thus possible to use the usual methods of stream, such as filter and map, to work with the result set. But it's best to rely on your database/SQL for operations that can be performed within the database, rather than trying to process it in the JVM. A WHERE clause or an aggregate function such as sum or count are more efficiently done in SQL, rather than trying to load the entire list in JVM and processing it using streams.
Before concluding CRUD aspects when using JPA, it's also worth noting that the read operations are pulling in all the fields of an entity. There are times when you would require a subset of fields, or fetching some aggregate value rather than loading the whole entity. In those cases, an approach called projection is a better fit. It can be considered as having a select query return only the required fields, and then using a constructor expression to map it to a data transfer object or value object, rather than getting the entity directly.
- Building a Game with Unity and Blender
- 新一代通用視頻編碼H.266/VVC:原理、標準與實現
- Unity Virtual Reality Projects
- Learning Informatica PowerCenter 10.x(Second Edition)
- Getting Started with SQL Server 2012 Cube Development
- Easy Web Development with WaveMaker
- ANSYS Fluent 二次開發指南
- C# and .NET Core Test Driven Development
- Troubleshooting Citrix XenApp?
- Python商務數據分析(微課版)
- 貫通Tomcat開發
- SAS編程演義
- Backbone.js Patterns and Best Practices
- 分布式系統架構與開發:技術原理與面試題解析
- 精通Oracle 12c 數據庫管理