Persistence Entity Manager

PersistenceEntityManager is a wrapper over JPA EntityManager to create, delete, update and query entities in persistence supporting QueryCriteria and CriteriaElements.

Create PersistenceEntityManager

PersistenceEntityManager can access different persistence units mapped to the system or subsystems.

Access the persistence unit of current bound system or subsystem:


	BackingBeanContext context = BackingBeanContext.getInstance();
	PersistenceEntityManager peManager = context.getPersistenceEntityManager();
Access the system persistence unit:

	BackingBeanContext context = BackingBeanContext.getInstance();
	PersistenceEntityManager peManager = context.getPersistenceEntityManager((Subsystem)null);
Access the persistence unit of a specified subsystem:
	
	BackingBeanContext context = BackingBeanContext.getInstance();
	PersistenceEntityManager peManager = context.getPersistenceEntityManager(subsystem);

For example,


	BackingBeanContext context = BackingBeanContext.getInstance();
	PersistenceEntityManager peManager = context.getPersistenceEntityManager();
	QueryCriteria queryCriteria = new QueryCriteria(Employee.class, 
		new CriteriaElement[]{DetachedCriteria.eq("type", Employee.Type.FULL_TIME)});
	List<Employee> employees = peManager.getEntityList(queryCriteria, null, null);

Transactions

In a JSF lifecycle, one transaction for each of the following phases: APPLY_REQUEST_VALUES, INVOKE_APPLICATION, and RENDER_RESPONSE. So do not need to explictly start and commit a transaction.

	BackingBeanContext context = BackingBeanContext.getInstance();
	PersistenceEntityManager peManager = context.getPersistenceEntityManager();
	Employee employee = new Employee(nid, name, type, hiredDate);
	peManager.createEntity(employee);
	
	// change and save it
	employee.setType(Employee.Type.FULL_TIME);
	employee = peManager.mergeEntity(employee);
	
	// delete it
	peManager.removeEntity(employee);
Entities are detached from persistence context at the end of each transaction.

Transaction listeners can be registered with current active transaction, and they will be called when the transaction is committed or rolled back. For example,


	TransactionListener listener = new DefaultTransactionListener() {
		@Override
		public PageNavigation committed(PhaseId phaseId) throws SystemException {
			// do something
			return null;
		}
		
		@Override
		public PageNavigation rolledback(PhaseId phaseId) throws SystemException {
			// do something		
			return null;
		}
	};
	TransactionPhaseListener.addTransactionListener(listener);

JTA

The default PersistenceEntityManager is based on Resource Local transaction type. To use JTA, JTA persistence contexts need to be injected into EntityManagers. For example,

public class JTAEntityManagerBean extends AbstractEntityManagerBean {
	
	@PersistenceContext(unitName="system") 
	private EntityManager systemEntityManager;
	
	@PersistenceContext(unitName="subsystem1")		
	private EntityManager subsystemOneEntityManager;
	
	@Override
	public EntityManager getEntityManager() {
  		if (queryDescriptor == null)
  			throw new IllegalArgumentException("queryDescriptor is null");

  		String persistenceUnit = queryDescriptor.getPersistenceUnit();
	  	if (persistenceUnit.equals("system"))
	  		return systemEntityManager;
	  	
	  	if (persistenceUnit.equals("subsystem1"))
	  		return subsystemOneEntityManager;
	  	
	  	throw new IllegalArgumentException("EntityManager not injected for persistence unit: " + persistenceUnit);
	}

	@Override
	public void clearEntityManagers(boolean allPersistenceUnits) {
		// EntityManager type is transaction, cleared at the end of each transaction.
		// so no need to clear(detach) entities.
	}

}
Register session beans in module implementation to override default PersistenceEntityManager implementation.

	@Override
	public void registerSessionBeans() {
		SessionBeanRegistry.register(PersistenceEntityManager.class, jndiName, JTAEntityManagerBean.class);
	}

Extend PersistenceEntityManager

PersistenceEntityManager can be extended, for example, to add application specific methods. First define an interface that extends PersistenceEntityManager. For example,

	public InventoryManager extends PersistenceEntityManager {
		public Integer getStock(Merchandise merchandise);
	}
The implementation class extends ResourceLocalEntityManagerBean or JTAEntityManagerBean depending on transaction type. For example,
	
	public InventoryManagerBean extends ResourceLocalEntityManagerBean {
		@Override
		public Integer getStock(Merchandise merchandise) {
			...
		}
	}
Register session beans in module implementation:

	@Override
	public void registerSessionBeans() {
		SessionBeanRegistry.register(InventoryManager.class, jndiName, InventoryManagerBean.class);
	}
An InventoryManager instance can be obtained in the following way:

	BackingBeanContext context = BackingBeanContext.getInstance();
	// access current bound system/subsystem
	InventoryManager inventoryManager = context.getPersistenceEntityManager(InventoryManager.class);
	// access specified subsystem (null for system)
	InventoryManager inventoryManager = context.getPersistenceEntityManager(InventoryManager.class, subsystem);	

Examples

Example 1: JPQL query

select nid and name of employees hired before a certain date and return the first 100 results.


	String query = "select nid, name from Employee where hiredDate<:hiredDate";
	Map<String, Object> parameterMap = new Hash<String, Object>();
	parameterMap.put("hiredDate", aDate);
	QueryCriteria queryCriteria = new QueryCriteria(Object[].class, 
		new DataDescriptor(Object[].class, true, false),
		query, QueryType.JPQL, parameterMap);
	List<Object[]> results = peManager.searchResults(queryCriteria, 0, 100);
	for (int i=0; i<results.size(); i++) {
		Object[] row = results[i];
		...
	}	
Or execute query without QueryCriteria:

	String query = "select nid,name from Employee where hiredDate<:hiredDate";
  	List results = peManager.executeQueryResultList(query, QueryType.JPQL, new Object[]{"hiredDate", aDate});
Example 2: JPQL update

	BackingBeanContext context = BackingBeanContext.getInstance();
	PersistenceEntityManager peManager = context.getPersistenceEntityManager();

	String query = "update Employee set type=:type where hiredDate<:hiredDate";
	peManager.executeUpdate(query, QueryType.JPQL, new Object[]{"type", Employee.Type.FULL_TIME, "hiredDate", aDate});
Example 3: Pagination

	BackingBeanContext context = BackingBeanContext.getInstance();
	PersistenceEntityManager peManager = context.getPersistenceEntityManager();

	CriteriaElement[] pqeList = new CriteriaElement[]{
		DetachedCriteria.desc("hiredDate")};
	QueryCriteria<Employee, Employee> queryCriteria = 
		new QueryCriteria<Employee, Employee>(Employee.class, pqeList);
	
	// pagination
	List<Employee> employees = peManager.getEntityList(queryCriteria, 0, 20);
	
	// row count
	int numberOfEmployees = peManager.getRowCount(queryCriteria);
Example 4: Create/update/delete

	BackingBeanContext context = BackingBeanContext.getInstance();
	PersistenceEntityManager peManager = context.getPersistenceEntityManager();
	
	// create
	Employee employee = new Employee(...);
	peManager.createEntity(employee);
	
	// update
	employee.setName("NewName");
	employee = peManager.mergeEntity(employee);
	
	// delete
	peManager.removeEntity(employee);
Batch update: change all the part-time employees hired before a certain date to full-time employees.

	Data aDate = ;
	peManager.updateProperties(Employee.class, new CriteriaElement[]{
		DetachedCriteria.lt("hiredDate", aDate),
		DetachedCriteria.eq("type", Employee.Type.PART_TIME)},
		new Object[]{"type", Employee.Type.FULL_TIME});
Batch delete: delete all the expense claims that are older than a certain date.

	Data aDate = ;
	peManager.deleteEntities(ExpenseClaim.class, new CriteriaElement[]{
		DetachedCriteria.lt("date", aDate)});
Example 5: Lock entity

	BackingBeanContext context = BackingBeanContext.getInstance();
	PersistenceEntityManager peManager = context.getPersistenceEntityManager();
	
	Employee employee = ;
	// reload with write lock
  	employee = peManager.lock(employee, true, LockModeType.WRITE);
  	
  	// retrieve entity with write lock
  	Employee employee = peManager.lock(Employee.class, 100, LockModeType.WRITE); 
 
Example 6: Detach entities/clear L2 cache

	BackingBeanContext context = BackingBeanContext.getInstance();
	PersistenceEntityManager peManager = context.getPersistenceEntityManager();
	
	Collection<Employee> employees = ;
	// detach employees, and clear L2 cache
	peManager.detachEntities(employees, true);
Example 7: Check whether an entity/property is loaded

	BackingBeanContext context = BackingBeanContext.getInstance();
	PersistenceEntityManager peManager = context.getPersistenceEntityManager();
	
	// check entity
	ExpenseClaim expenseClaim = ;
	boolean loaded = peManager.isLoaded(expenseClaim);
	
	// check property
	boolean loaded = peManager.isLoaded(expenseClaim, "expenseClaimItems");