I
- type of the persistent object and transport object id. This type
should be immutable. It is critical this type implements equals()
and hashCode() correctly.P
- type of model persistent objectT
- type of the transport objectF
- type of the associated filterS
- type of the associated sort specification typepublic abstract class AbstractBaseDao<I extends Serializable,P extends Storable<I>,T extends Transportable<? super T,I>,F,S> extends Object implements BaseDao<I,P,T,F,S>
This class must remain state-less so it is thread safe.
Some notes on primary keys:
A candidate key is a column or a set of columns that could be used to identify a particular row in a table. To become a primary key, a candidate key must satisfy the following properties:
A natural key is a key with business meaning: an attribute or combination of attributes that is unique by value of its business semantic (U.S. Social Security Number for example). If a candidate key attribute has meaning outside the database context, it is a natural key, whether or not it is automatically generated.
Experience has shown that natural keys almost always cause problems in the long run. A good primary key must be unique, constant and required. Few entity attributes satisfy the requirements, and some that do can't be efficiently indexed by SQL databases (although this is an implementation detail and shouldn't be the primary motivation for or against a particular key). Natural keys can only be found only by combining several columns in a composite natural key. These composite keys, although certainly appropriate for some relations (like a link table in a many-to-many relationship), usually make maintenance, ad-hoc queries, and schema evolution much more difficult.
For these reasons it is recommended to use synthetic identifiers, also called surrogate keys. Surrogate keys have not business meaning - they are unique values generated by the database or application. Application users ideally don't see or refer to these key values; they're part of the system internals. Introducing surrogate key column is also appropriate in a common situation: If there are no candidate keys, a table is by definition not a relation as defined by the relational model -it permits duplicated rows- and so you have to add a surrogate key column.
Some notes on composite keys:
If an entity defines a composite key, it is more elegant to define a separate composite identifier class that declares just the key properties, and this is actually forced in this class by the type-parameter I (The entity's id is typed with the generic type).
Strategies for handling composite keys:
@Embeddable
, like a regular component. Include a property of this
component in your entity class, and map it with @Id
for an
application assigned strategy.@EmbeddedId
.@IdClass
and specify the name of your
encapsulated identifier class.
For example, suppose you have an User
entity where the primary key
consists of a USERNAME and DEPARTMENT_NUMBER. Then an UserId
class
could be created to keep the primary key attributes:
public class UserId implements Serializable { private String username; private int departmentNumber; ... // Default constructor required by JPA. // Constructor expects primary key attributes and validates they are not null. // Just setters are exposed. // override equals and hasCode properly. }As for all component mappings, you can define extra mapping attributes on the fields of the entity's class. To map the composite key for
User
, set the generation strategy to application assigned by omitting the
@GeneratedValue
annotation.
Strategy 1 (This requires to annotate UserId
and it is not
necessary to override properties, they are override in case we need to
change the column name for example).
@Id @AttributeOverrides ( { @AttributeOverride(name="username", column = @Column(name="USERNAME")), @AttributeOverride(name="departmentNumber", column = @Column(name="DEPARTMENT_NUMBER")) } ) private UserId userId;Strategy 2 (This does not require
UserId
to be annotated).
@EmbeddedId @AttributeOverrides ( { @AttributeOverride(name="username", column = @Column(name="USERNAME")), @AttributeOverride(name="departmentNumber", column = @Column(name="DEPARTMENT_NUMBER")), } ) private UserId userId;Strategy 3 (This does not require
UserId
to be annotated).
@Entity @Table(name="Users") @IdClass(UserId.class) public class User { @Id private String username; @Id private int departmentNumber; ... }
Modifier | Constructor and Description |
---|---|
protected |
AbstractBaseDao(Class<P> entityClass)
Construct DAO and initialize query predicate generator.
|
Modifier and Type | Method and Description |
---|---|
long |
count(F filter,
DataStoreContext context)
Gets the number of persist objects based on a filter criteria.
|
List<P> |
find(F filter,
SortSpecification<S> sortSpec,
DataStoreContext context)
Get the set of persist objects based on the given filter criteria.
|
Page<P> |
find(F filter,
SortSpecification<S> sortSpec,
PageRequest pageRequest,
DataStoreContext context)
Get the set of persist objects based on the given filter criteria.
|
List<P> |
findAll(SortSpecification<S> sortSpec,
DataStoreContext context)
Gets all the persistent objects.
|
P |
get(Id<T,I> id,
DataStoreContext context)
Get the persistent object with the given id.
|
protected abstract javax.persistence.criteria.Predicate |
getQueryPredicate(F filter,
javax.persistence.criteria.CriteriaBuilder builder,
javax.persistence.criteria.Root<P> root)
Augment the underlying database query with specifics to be included as
part of the where clause
|
protected QueryPredicateGenerator<P> |
getQueryPredicateGenerator()
Get the query predicate generator for this type of entity
|
protected abstract javax.persistence.metamodel.SingularAttribute<? super P,?> |
getSingularAttribute(S sortAttribute)
Gets the singular attribute (JPA entity attribute -Column- definition)
|
protected static <R extends Serializable,E extends Storable<R>,D extends Transportable<? super D,R>> |
updateDependents(Collection<E> currentDependents,
Collection<D> newDependents,
DependentUpdater<E,D> updater)
Updates a collection of dependent entities in a one-to-many relation
where this DAO represents the independent entity.
|
public P get(Id<T,I> id, DataStoreContext context)
BaseDao
public List<P> find(F filter, SortSpecification<S> sortSpec, DataStoreContext context)
BaseDao
public Page<P> find(F filter, SortSpecification<S> sortSpec, PageRequest pageRequest, DataStoreContext context) throws IndexOutOfBoundsException
BaseDao
find
in interface BaseDao<I extends Serializable,P extends Storable<I>,T extends Transportable<? super T,I>,F,S>
filter
- Filter criteriasortSpec
- sort specificationpageRequest
- the page of data desiredcontext
- data store contextIndexOutOfBoundsException
- if page request is for a page outside
the maximum or minimum pages for the requestpublic List<P> findAll(SortSpecification<S> sortSpec, DataStoreContext context)
BaseDao
public long count(F filter, DataStoreContext context)
BaseDao
protected QueryPredicateGenerator<P> getQueryPredicateGenerator()
protected abstract javax.persistence.criteria.Predicate getQueryPredicate(F filter, javax.persistence.criteria.CriteriaBuilder builder, javax.persistence.criteria.Root<P> root)
filter
- The input filter from which the criteria is set.builder
- the criteria builder object for augmenting the query
objectroot
- the root object type associated with the queryprotected abstract javax.persistence.metamodel.SingularAttribute<? super P,?> getSingularAttribute(S sortAttribute)
sortAttribute
- sort attribute to map a column to.protected static <R extends Serializable,E extends Storable<R>,D extends Transportable<? super D,R>> void updateDependents(Collection<E> currentDependents, Collection<D> newDependents, DependentUpdater<E,D> updater)
E
- type of the dependent persistent object.D
- type of the dependent transport object.currentDependents
- entities currently persisted as dependents.newDependents
- new dependent entities.updater
- dependent updater.Copyright © 2015. All Rights Reserved.