Build your DAO layer by extending standard persistent entity DAO interfaces / abstract implementations which already provide most of the usual DAO functionality.
So, you have your business domain model implemented using the standard persistent entity model. The next step is to write the actual DAO classes working with your persistent entities. These classes essentially form the core of your DAO layer - now this is the part when the real fun begins!
DAO Fusion provides standard DAO interfaces and abstract implementations based on JPA / Hibernate persistence APIs for you to extend. This way, generic DAO operations and actual business-related operations are cleanly separated from each other, having a significant impact on the overall code maintainability.
PersistentEntityDao interface represents a generic persistent entity DAO contract defining the standard set of operations for the given entity type (specified as a class parameter). PersistentEntityDao works with Persistable instances which use a single primary key column type to denote their database identity. Each PersistentEntityDao implementation must define the associated implicit persistent entity class via the getEntityClass method - this is the root entity the given DAO works with. Users can therefore choose between two strategies of associating DAOs with persistent entities:
Note that PersistentEntityDao contains methods that work with subclasses of the implicit entity class as well as convenience methods working with the implicit entity class directly. Having one DAO interface for an entity hierarchy is particularly useful when using persistent enumerations (instances sharing the same set of properties are primarily distinguished by their type).
Here is a brief PersistentEntityDao method listing for you to get a basic idea of the standard DAO functionality:
public interface PersistentEntityDao<T extends Persistable<ID>, ID extends Serializable> { /** * Returns the implicit persistent entity class the DAO works with. */ Class<T> getEntityClass(); /** * Retrieves a persistent instance. */ <S extends T> S get(ID id, Class<S> targetEntityClass); /** * Retrieves all persistent instances. */ <S extends T> List<S> getAll(Class<S> targetEntityClass); /** * Persists a transient instance or updates a detached instance. */ <S extends T> S saveOrUpdate(S entity); /** * Deletes a persistent instance. */ void delete(T entity); /** * Deletes a persistent instance. */ <S extends T> void delete(ID id, Class<S> targetEntityClass); /** * Deletes all persistent instances. */ <S extends T> int deleteAll(Class<S> targetEntityClass); /** * Refreshes a persistent or a detached instance by synchronizing * its state with the database. */ void refresh(T entity); /** * Retrieves a list of persistent instances. */ <S extends T> List<S> query(PersistentEntityCriteria entityCriteria, Class<S> targetEntityClass); /** * Returns a single persistent instance (if available). */ <S extends T> S uniqueResult(PersistentEntityCriteria entityCriteria, boolean returnNullOnMultipleResults, Class<S> targetEntityClass); /** * Returns the total number of instances persisted within the database. */ <S extends T> int count(PersistentEntityCriteria entityCriteria, Class<S> targetEntityClass); /** * Returns the total number of all instances persisted within the database. */ <S extends T> int countAll(Class<S> targetEntityClass); }
As you can see, there are several kinds of operations defined by this interface for the given entity class and its subclasses:
Note that each method accepting the Class<S> targetEntityClass parameter has a "direct" (convenience) version without this parameter that works with the implicit persistent entity class. For example:
/** * Retrieves a persistent instance (generic version). */ <S extends T> S get(ID id, Class<S> targetEntityClass); /** * Retrieves a persistent instance (convenience version). */ T get(ID id);
Even with this simple set of operations, you are able to cover most of the DAO functionality for your entity classes without having to worry about any Hibernate-specific implementation details.
PersistentEnumerationDao as an extension of the PersistentEntityDao interface works with PersistentEnumeration instances. The goal of this interface is to define useful lookup operations using the name field declared by PersistentEnumeration:
public interface PersistentEnumerationDao<T extends PersistentEnumeration> extends PersistentEntityDao<T, Long> { /** * Retrieves a persistent enumeration by its name. */ <S extends T> S getByName(String name, Class<S> targetEntityClass); /** * Retrieves a list of persistent enumerations by their name values. */ <S extends T> List<S> getByNames(Class<S> targetEntityClass, String... names); }
Note that PersistentEnumerationDao follows the same method pattern as PersistentEntityDao shown above.
BaseHibernateDataAccessor is the base class for all standard DAO implementations, providing data access through JPA / Hibernate persistence APIs. This class requires you to implement the abstract getHibernateEntityManager method which serves as the access point to Hibernate Session instances:
public abstract class BaseHibernateDataAccessor { /** * Returns an open HibernateEntityManager instance providing access * to the Hibernate Session. */ protected abstract HibernateEntityManager getHibernateEntityManager(); }
The reason for declaring an abstract getHibernateEntityManager method is to give users free hands when it comes to entity manager instance lookup. The most convenient method implementation pattern is to rely on entity manager instance injection via the @PersistenceContext annotation (within the JPA persistence context) and simply returning the injected instance. Alternatively, the entity manager instance can be created directly via the EntityManagerFactory. DAO Fusion doesn't restrict you regarding the entity manager lookup strategy - it just asks you to implement it the way you prefer. Note that all data access happens solely through the Hibernate Criteria API to ensure database portability. This makes DAO Fusion generic and reusable across multiple database vendors, assuming the provided dialect is up to date for the given database.
There are two abstract implementations for the two DAO interfaces mentioned above: AbstractHibernateEntityDao and AbstractHibernateEnumerationDao (the latter one simply extends the generic AbstractHibernateEntityDao implementation). These two classes are the ones you will extend when building your custom DAO implementations.
DAO Fusion tries to do its best when it comes to defining persistent entity query constraints via the PersistentEntityCriteria interface. You are, however, free to use the underlying Hibernate Criteria API on your own using the getHibernateCriteria, getSession and getCriteria methods. DAO Fusion doesn't try to hide the Hibernate Criteria API away from you, it just defines its own flexible persistent entity criteria API that should cover 90% of the most typical use cases out there. In fact, using the Hibernate Criteria API directly in your DAO implementations should be the last resort for all but the most complex cases where a custom PersistentEntityCriteria implementation is not possible (remember that even custom PersistentEntityCriteria implementations can be efficiently and consistently reused between multiple DAOs as opposed to using Hibernate Criteria API directly in your DAO implementations).
Transactions aim to improve integrity and consistency of your data, grouping data access operations into logical units of work which are atomic and properly isolated from each other within concurrent (multi-user) environments. Transactions promote data consistency through its atomicity, ensuring that only valid data will be written to the database. These concepts essentially follow the ACID (Atomicity, Consistency, Isolation, Durability) principle of database transactions.
Since Object-relational mapping frameworks such as Hibernate require a transaction in order to trigger the synchronization between the object cache (session) and the database, the bottom line is simple - you have to care about transactions in your DAO layer in any case when using DAO Fusion.
Standard persistent entity DAO implementations don't care about transactions - but should they? What if someone wants to handle transactions manually using the programmatic transaction model or create transactional AOP proxies using the declarative transaction model? To maintain the generic nature of the DAO concept, DAO Fusion lets its users handle transactions within the context of DAO method calls completely on their own. The use of a specific transaction strategy based on a transaction model as well as proper transaction attributes always depend on specific business requirements of your project and should be therefore carefully considered in terms of concurrency, performance and data integrity. See the transaction management page for more information on this topic.
Let's build a sample persistent entity DAO on top of PersistentEntityDao / AbstractHibernateEntityDao classes. There are basically two ways to accomplish this task:
As a solid Java developer having things like code maintainability always in mind (not mentioning those hot chicks in the marketing department), you might write your DAO classes like this:
@Component public class EntityManagerHolder { @PersistenceContext private HibernateEntityManager entityManager; public HibernateEntityManager getEntityManager() { return entityManager; } public void setEntityManager(HibernateEntityManager entityManager) { this.entityManager = entityManager; } } public abstract class EntityManagerAwareEntityDao<T extends Persistable<ID>, ID extends Serializable> extends AbstractHibernateEntityDao<T, ID> { @Autowired private EntityManagerHolder entityManagerHolder; @Override protected HibernateEntityManager getHibernateEntityManager() { return entityManagerHolder.getEntityManager(); } } public interface OrderDao extends PersistentEntityDao<Order, Long> { // add some business-related methods here } @Component public class OrderDaoImpl extends EntityManagerAwareEntityDao<Order, Long> implements OrderDao { public Class<Order> getEntityClass() { return Order.class; } // add business-related method implementations here }
In this example we use Spring's JPA support to inject an open entity manager instance into the EntityManagerHolder bean. EntityManagerAwareEntityDao acts as a base class for domain-specific DAO implementations, providing the getHibernateEntityManager method implementation via the EntityManagerHolder.