All enterprise applications need to perform operations on the underlying datasource, and Hibernate supports this quite well with it's Hibernate Query Language .
UML also allows you to specify queries, be it in a more generic language. For this purpose OCL can
be used, which supports body
constructs since OCL 2.0. Although you can choose
to override any generated query using a tagged value specifying your custom query it is
strongly recommended to use OCL since this will guarantee your code to remain portable over different
technologies. If you don't want to get to know OCL and have no problem sticking to Hibernate
then you might consider using tagged values instead.
Finder methods require the query flag
to be set, usually operations with this flag have
the commercial at
symbol '@' in front of their name when displayed in diagrams. Make sure
you model the operation in classifier scope, in diagrams this will show them as underlined.
Actually, classifier scoped operations go into the DAO while instance scoped operations go into the
entity's implementation class (they are considered to be business operations).
For simple finders the cartridge will be able to generate the proper HQL without even requiring you
to write any OCL constraint! Just make sure to enable that query
flag and name the operation
findByXXX(XXX : type)
where XXX stands for the property on which you would like to search,
for example: findByUserName(userName : String)
. The finder must return a collection type
or the type of the underlying entity. In the former case the query is simply executed and the results
are returned, in the latter case the first element from the result set is returned
after being cast to the proper type. This is all done automatically and you won't need to worry about
anything, there's no need to write any HQL yourself or to implement any method. Check the entity's DAO
to learn what else you can do with the newly generated code (such as automatic conversion of the
result set into value objects).
The documentation discussing the modeling of queries in UML is found here: Query Translation-Library Modeling . The tagged value overriding queries using Hibernate QL directly is found here: @andromda.hibernate.query .
Car.hbm.xml
Car.java
CarImpl.java
CarDao.java
CarDaoBase.java
CarDaoImpl.java
CarType.java
CarSearchCriteria.java
CriteriaSearch.java
CriteriaSearchParameter.java
CriteriaSearchConfiguration.java
Person.hbm.xml
Person.java
PersonImpl.java
PersonDao.java
PersonDaoBase.java
PersonDaoImpl.java
RentalService.java
RentalServiceBase.java
RentalServiceImpl.java
ejb/RentalService.java
ejb/RentalServiceBean.java
ejb/RentalServiceHome.java
Notice how one of the classes has been labeled <<Criteria>> and used in one of the queries. This will yield a specific piece of code allowing a search on any combination of existing properties.
Tagged values may be added to the attributes of such a class. They are interesting when you want to
wire the attributes to specific properties of the domain model. You can
also set the comparator for the criteria search (equal, like, less, ...) or define certain attributes
to be included in the search even if they are null
.
You can even activate result set ordering (ascending / descending) by just applying two tagged values
to one or more criteria search attributes. For more details
go here:
Tagged Values
.
These criteria objects allow to set the maximum number of elements to fetch, just do something like this:
// we need to find cars with name 'audi' onlyCarSearchCriteria searchCriteria =newCarSearchCriteria(null,"audi");// after 1200 cars are found we stop searchingsearchCriteria.setMaximumResultSize(newInteger(1200));// initiate the search by calling the DAOList audis = getCarDao().findByCriteria(searchCriteria);
It's allowed to override queries such as finders in the DAO, just override the appropriate method
in an entity's DAO implementation class. What follows is an example of a code snippet
overriding a generated HQL query (example taken from a ficticous UserDAOImpl
class):
publicList findActiveUsers(inttransform) {// the next query is user-specified and overrides the one generated in super.findActiveUsers(int transform)returnsuper.findActiveUsers(transform,"from org.andromda.test.Users as user where user.exitDate is null"); }
You might consider doing this when you think the generated query is not performant enough, or when you need to do something which is so complex the OCL translation can't properly handle it.
The next section will cover the modeling of exceptions, click here to go to that section.