Wednesday, 25 June 2008

Java Persistence with Hibernate By Christian Bauer and Gavin King

Just now i completed reading Java Persistence with Hibernate By Christian Bauer and Gavin King

I think readers new to hibernate will find this article worth reading.I really enjoyed practicing all examples from the article.

Also i thought documentation provided in hibernate site is very interesting and really worth to read.

Good book and it is surely a book needed for all developers wanted to learn hibernate.

Below are the points i wanted to share with readers from this book.

1) Hibernate is an open source ORM service implementation.

2) Relational database management systems aren’t specific to Java, nor is a relational database specific to a particular application. This important principle is known as data independence.

3) Java objects define two different notions of sameness:
a) Object identity (roughly equivalent to memory location, checked with a==b)
b) Equality as determined by the implementation of the equals() method (also called equality by value)

4) A Hibernate Session is many things in one. It’s a single-threaded nonshared object that represents a particular unit of work with the database.It has the persistence manager API you call to load and store objects.(The Session internals consist of a queue of SQL statements that need to be synchronized with the database at some point and a map of managed persistence instances that are monitored by the Session.)

5) Automatic dirty checking. This feature saves you the effort of explicitly asking Hibernate to update the database when you modify the state of an object inside a unit of work.

6) Method chaining—Method chaining is a programming style supported by many Hibernate interfaces. This style is more popular in Smalltalk than in Java and is considered by some people to be less readable and more
difficult to debug than the more accepted Java style. However, it’s convenient in many cases, such as for the configuration snippets you’ve seen in this section. Here is how it works: Most Java developers declare setter or adder methods to be of type void, meaning they return no value; but in Smalltalk, which has no void type, setter or adder methods usually return the receiving object. We use this Smalltalk style in some code examples,but if you don’t like it, you don’t need to use it. If you do use this coding style, it’s better to write each method invocation on a different line. Otherwise,it may be difficult to step through the code in your debugger.

7) Hibernate automatically detects object state changes in order to synchronize the updated state with the database.It’s usually safe to return a different object from the getter method than the object passed by Hibernate to the setter. Hibernate compares the objects by value—not by object identity—to determine whether the property’s persistent state needs to be updated

8) If your table doesn't have an index column, and you still wish to use List as the property type, you should map the property as a Hibernate bag. A bag does not retain its order when it is retrieved from the database, but it may be optionally sorted or ordered.

9) For a table with a composite key, you may map multiple properties of the class as identifier properties. The composite-id element accepts key-property property mappings and key-many-to-one mappings as child elements.

10) The component element maps properties of a child object to columns of the table of a parent class. Components may, in turn, declare their own properties, components or collections.

11) Finally, polymorphic persistence requires the declaration of each subclass of the root persistent class. For the table-per-class-hierarchy mapping strategy, the subclass declaration is used.

Alternatively, each subclass may be mapped to its own table (table-per-subclass mapping strategy). Inherited state is retrieved by joining with the table of the superclass. We use the joined-subclass element.

12) You may specify a bidirectional many-to-many association simply by mapping two many-to-many associations to the same database table and declaring one end as inverse (which one is your choice, but it can not be an indexed collection).

Changes made only to the inverse end of the association are not persisted. This means that Hibernate has two representations in memory for every bidirectional association, one link from A to B and another link from B to A. This is easier to understand if you think about the Java object model and how we create a many-to-many relationship in Java:


category.getItems().add(item); // The category now "knows" about the relationship
item.getCategories().add(category); // The item now "knows" about the relationship

session.persist(item); // The relationship won't be saved!
session.persist(category); // The relationship will be saved



13) Using an idbag Hibernate provides a feature that allows you to map many to many associations and collections of values to a table with a surrogate key.

The idbag element lets you map a List (or Collection) with bag semantics.

As you can see, an idbag has a synthetic id generator, just like an entity class! A different surrogate key is assigned to each collection row. Hibernate does not provide any mechanism to discover the surrogate key value of a particular row, however.

Note that the update performance of an is much better than a regular bag! Hibernate can locate individual rows efficiently and update or delete them individually, just like a list, map or set.

14) The most basic SQL query is to get a list of scalars (values).

15) Returning multiple entities

Column alias injection is needed in the following query (which most likely will fail):

sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class)

The intention for this query is to return two Cat instances per row, a cat and its mother. This will fail since there is a conflict of names since they are mapped to the same column names and on some databases the returned column aliases will most likely be on the form "c.ID", "c.NAME", etc. which are not equal to the columns specificed in the mappings ("ID" and "NAME").

The following form is not vulnerable to column name duplication:


sess.createSQLQuery("SELECT {cat.*}, {mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class)


This query specified:

the SQL query string, with placeholders for Hibernate to inject column aliases

the entities returned by the query

The {cat.*} and {mother.*} notation used above is a shorthand for "all properties". Alternatively, you may list the columns explicity, but even in this case we let Hibernate inject the SQL column aliases for each property. The placeholder for a column alias is just the property name qualified by the table alias. In the following example, we retrieve Cats and their mothers from a different table (cat_log) to the one declared in the mapping metadata. Notice that we may even use the property aliases in the where clause if we like


16) The DetachedCriteria class lets you create a query outside the scope of a session, and then later execute it using some arbitrary Session.


DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
.add( Property.forName("sex").eq('F') );

Session session = ....;
Transaction txn = session.beginTransaction();
List results = query.getExecutableCriteria(session).setMaxResults(100).list();
txn.commit();
session.close();



17) Associations and joins

We may also assign aliases to associated entities, or even to elements of a collection of values, using a join.


from Cat as cat
inner join cat.mate as mate
left outer join cat.kittens as kitten

from Cat as cat left join cat.mate.kittens as kittens

from Formula form full join form.parameter param


18) Hibernate defines and supports the following object states:

Transient - an object is transient if it has just been instantiated using the new operator, and it is not associated with a Hibernate Session. It has no persistent representation in the database and no identifier value has been assigned. Transient instances will be destroyed by the garbage collector if the application doesn't hold a reference anymore. Use the Hibernate Session to make an object persistent (and let Hibernate take care of the SQL statements that need to be executed for this transition).

Persistent - a persistent instance has a representation in the database and an identifier value. It might just have been saved or loaded, however, it is by definition in the scope of a Session. Hibernate will detect any changes made to an object in persistent state and synchronize the state with the database when the unit of work completes. Developers don't execute manual UPDATE statements, or DELETE statements when an object should be made transient.

Detached - a detached instance is an object that has been persistent, but its Session has been closed. The reference to the object is still valid, of course, and the detached instance might even be modified in this state. A detached instance can be reattached to a new Session at a later point in time, making it (and all the modifications) persistent again. This feature enables a programming model for long running units of work that require user think-time. We call them application transactions, i.e. a unit of work from the point of view of the user.

19) Representing data in XML

Hibernate has no built-in functionality to store data in an XML format; it relies on a relational representation and SQL, and the benefits of this strategy should be clear. On the other hand, Hibernate can load and present data to the application developer in an XML format. This allows you to use a sophisticated set of tools without any additional transformation steps.

Let’s assume that you work in default POJO mode and that you quickly want to obtain some data represented in XML. Open a temporary Session with the EntityMode.DOM4J:

What is returned here is a dom4j Element, and you can use the dom4j API to read and manipulate it.

Below example illustrates the usage.



Session dom4jSession = session.getSession(EntityMode.DOM4J);
Element userXML =(Element) dom4jSession.load(Representative.class,new Long(10));

try {
FileOutputStream fileOutputStream=new FileOutputStream("C://temp//invalid.txt");
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter(fileOutputStream,format);
writer.write( userXML );
} catch (IOException ex) {
throw new RuntimeException(ex);
}


You can change this default XML representation by adding node attributes to
your Hibernate mapping metadata:


20) With some Hibernate tricks, you can switch the mapping strategy for a particular subclass. For example, you can map a class hierarchy to a single table, but for a particular subclass, switch to a separate
table with a foreign key mapping strategy, just as with table per subclass. This is possible with the mapping element:

The join element groups some properties and tells Hibernate to get them from a secondary table.In this example, it separates the CreditCard properties from the table per hierarchy into the CREDIT_CARD table. The CREDIT_CARD_ID column of this table is at the same time the primary key, and it has a foreign key constraint
referencing the BILLING_DETAILS_ID of the hierarchy table.

At runtime, Hibernate executes an outer join to fetch BillingDetails and all subclass instances polymorphically:


select
BILLING_DETAILS_ID, BILLING_DETAILS_TYPE, OWNER,
CC.CC_NUMBER, CC.CC_EXP_MONTH, CC.CC_EXP_YEAR,
BA_ACCOUNT, BA_BANKNAME, BA_SWIFT
from
BILLING_DETAILS
left outer join
CREDIT_CARD CC
on BILLING_DETAILS_ID = CC.CREDIT_CARD_ID


21) An unordered collection that permits duplicate elements is called a bag.

22) What is the effect of cascade on inverse? Many new Hibernate users ask this question. The answer is simple: The cascade attribute has nothing to do with the inverse attribute. They often appear on the same collection mapping. If you map a collection of entities as inverse="true", you’re controlling the generation of SQL for a bidirectional association mapping. It’s a hint that tells Hibernate you mapped the same foreign key column twice. On the other hand, cascading is used as a convenience feature.If you decide to cascade operations from one side of an entity relationship to associated entities, you save the lines of code needed to manage the state of the other side manually. We say that object state becomes transitive. You can cascade state not only on collections of entities, but on all entity association mappings. cascade and inverse have in common the fact that they don’t appear on collections of value types or on any other value-type mappings. The rules for these are implied by the nature of value types.

23) IDBAG mapping is much smarter than BAG but requires ID column in the table of dependent objects. When we change collection content or update its members Hibernate will issue only necessary SQL update statements. If we delete one object from the collection, then Hibernate will execute only one SQL delete statement. IDBAG mapping looks as the following:

This article highlights more between Hibernate BAG vs IDBAG Performance.

24) To more more about inverse="true" attribute please follow this article

Indexed collections (lists and maps) don’t work, because Hibernate won’t initialize or maintain the index column if the collection is inverse. In other words, a many-to-many association can’t be mapped with indexed collections on both sides.

25) There are three ways to express queries in Hibernate:

-> Hibernate Query Language (HQL), and the subset standardized as JPA QL:

session.createQuery("from Category c where c.name like 'Laptop%'");
entityManager.createQuery("select c from Category c where c.name like 'Laptop%'");

-> Criteria API for query by criteria (QBC) and query by example (QBE):


session.createCriteria(Category.class).add( Restrictions.like("name", "Laptop%") );

-> Direct SQL with or without automatic mapping of resultsets to objects:

session.createSQLQuery("select {c.*} from CATEGORY {c} where NAME like 'Laptop%'").addEntity("c",Category.class);

26) If you need disjunction (or), there are two options.

The first is to use Restrictions.or() together with Restrictions.and():

session.createCriteria(User.class)
.add(
Restrictions.or(
Restrictions.and(
Restrictions.like("firstname", "G%"),
Restrictions.like("lastname", "K%")
),
Restrictions.in("email", emails)
)
);

The second option is to use Restrictions.disjunction() together with Restrictions.conjunction():

session.createCriteria(User.class)
.add( Restrictions.disjunction()
.add( Restrictions.conjunction()
.add( Restrictions.like("firstname", "G%") )
.add( Restrictions.like("lastname", "K%") )
)
.add( Restrictions.in("email", emails) )
)


About the Authors

Christian Bauer is a member of the Hibernate developer team. He works as a trainer, consultant, and product manager for Hibernate, EJB 3.0, and JBoss Seam at JBoss, a division of Red Hat. With Gavin King, Christian wrote Hibernate in Action.

Gavin King is the founder of the Hibernate and JBoss Seam projects, and a member of the EJB 3.0 (JSR 220) expert group. He also leads the Web Beans JSR 299, a standardization effort involving Hibernate concepts, JBoss Seam, JSF, and EJB 3.0. Gavin works as a lead developer at JBoss, a division of Red Hat.

Hope you enjoy reading this book

1 comment:

Anonymous said...

Additionally, the lawyer may be well aware of the type of business you run and can efficiently handle any issues related to it.

After personal injury lawyers have been successful performing all of the duties explained here, they may be
able to obtain the highest judgment possible for their clients.
The CFA is a risk sharing mechanism that enables
the lawyer and client to spread between them the risk of
the claim being unsuccessful.

Feel free to surf to my web-site www.personal-injury-lawyers-blog.com