hibernate

74
Hibernate -Prashant Kalkar 1

Upload: prashant-kalkar

Post on 14-Apr-2017

132 views

Category:

Technology


0 download

TRANSCRIPT

Hibernate- Prashant Kalkar

1

Object Relational Mismatch

Problem of Granularity

Granularity is the extent to which a system is broken down into small parts.Mapping fine-grained classes to coarse-grained tables.

Object Relational Mismatch contd..

© Nihilent Technologies 2011

Problem of Subtypes

• Mapping of Inheritance to database• Polymorphic relationships & Queries

Object Relational Mismatch contd..

Problems of Associations

• Object References Vs Foreign Keys.

• References are inherently directional while foreign keys are not. For bidirectional relationship two object references are required.

• Navigation for Object References are possible, but there is no meaning of Navigation for foreign Keys.

• Problem of Many-to-Many – Relational entities does not support true many-to-many relationship while its possible in Objects.

Object Relational Mismatch contd..

Problem of Data Navigation

• Most natural way of accessing object is by walking the object network likeuser.getBillingDetails().getAccountNumber()

• Accessing relational data you will require joins.

Hibernate, JPA

• Hibernate is full object/relational mapping tool.

• JPA (Java Persistence API) – It’s the part of EJB 3 specification that deals with Persistence.

• Hibernate is the implementation of JPA.

• Hibernate parts✓ Hibernate Core – Native API with XML Mapping support. ✓ Hibernate Annotations – JPA annotations supported. ✓ Hibernate EntityManager – Supports programming interfaces, lifecycle rules and query features of the JPA specifications.

Hibernate Project

• Starting Hibernate Project• Download the Hibenate 3. • Create Project directory (Web Project in Eclipse).• Add the Hibernate Jars to libs directory. Also add the database driver jar file.• Options to start the application (Hibernate Tools)

✓ Create Entity classes with Annotations – Generate DAO, Database schema.✓ Create hbm mapping files – Generate Pojos, Generate DAO, and schema.

Hibernate Tools (Eclipse Plug-in)

POJOs (Entities)

•Pojos or Entity classes are classes like JavaBeans and generally have accessor methods.•A no argument constructor is required for Hibernate POJOs.•The class should not be declared as final (nor has final methods) (Required for Proxy creation).•Simple class mapping

public class Message {private Long Id;private String text;

}

• Hibernate Mapping XML of corresponding class<hibernate-mapping>

<class name=“hello.Message” table=“MESSAGES”>

<id name=“id” column=“MESSAGE_ID”><generator class=“increment” />

</id>

<property name=“text” column=“MESSAGE_TEXT” />

</class></hibernate-mapping>

Hibernate APIs

• Session – Single threaded non shared object, that manages one unit of work with the database. It provides persistence manager API.

•Eg. session.save(..), session.saveOrUpdate(), session.load(), session.get() etc.

• Transaction – Transaction api can be used to define the transactional boundaries programmatically. Like session.beginTransaction(), transaction.commit(), transaction.rollback().

• Query – This interface allows us to create queries, bind parameters etc. It supports HQL (Hibernate Query Language) or plain SQL.

• SessionFactory – Use to create session Objects. The SessionFactory should be instantiated once during application initialization. The single instance should then be used by all code in a particular process, and any Session should be created using this single SessionFactory. The SessionFactory is thread-safe and can be shared.

Hibernate Configuration

• Hibernate.cfg.xml (Hibernate Configuration file) •Should be placed at the root of the classpath, like source directory (src) outside of any package.

•Sample file<hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class"> org.hsqldb.jdbcDriver </property> <property name="hibernate.connection.url"> jdbc:hsqldb:hsql://localhost </property> <property name="hibernate.connection.username"> sa </property>

<property name="hibernate.dialect"> org.hibernate.dialect.HSQLDialect </property> <!-- Show and print nice SQL on stdout --> <property name="show_sql">true</property> <property name="format_sql">true</property>

<!-- List of XML mapping files --> <mapping resource="hello/Message.hbm.xml"/> </session-factory></hibernate-configuration>

Hibernate Configuration contd…

• Hibernate.properties (sample)

hibernate.connection.driver_class = org.hsqldb.jdbcDriverhibernate.connection.url = jdbc:hsqldb:hsql://localhosthibernate.connection.username = sahibernate.dialect = org.hibernate.dialect.HSQLDialect

hibernate.show_sql = truehibernate.format_sql = true

•Properties defined in hibernate.properties can be overridden in hibernate.cfg.xml file (if defined).

Creating Hibernate Session Factory

• Should be created once, and used through out the application.

public class HibernateUtil { private static SessionFactory sessionFactory; static {

try { sessionFactory=new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { // Alternatively, you could look up in JNDI here return sessionFactory; } }•Configuration() – Tries to load the hibernate.properties into the Configuration object. •Configuration().configure() – Will try to load the hibernate.cfg.xml file, you don’t need to call this method if you are not providing xml file.

Hibernate Annotations

• Hibernate annotation related jars are required. • Remove the hbm.xml files and update the Message class with annotations.

@Entity@Table(name = "MESSAGES")public class Message { @Id @GeneratedValue @Column(name = "MESSAGE_ID") private Long id;

@Column(name = "MESSAGE_TEXT") private String text; .....}

• Update the Hibernate.cfg.xml file to include the new Annotated classes instead of hbm.xml files.

<hibernate-configuration> <session-factory> <!-- ... Many property settings ... -->

<!-- List of annotated classes--> <mapping class="hello.Message"/> </session-factory> </hibernate-configuration>

• Update the SessionFactory code created. Use AnnotationConfiguration class instead of Configuration class.

Identifier Generators

• Identifier Generators – To generate values for the table primary key columns (Entity Identifier attribute). • Normally used Identifiers

•Native (JPA – AUTO) – Picks identifier supported by the underlying database. • Identity (JPA – IDENTITY) – Support identity columns in DB2, MySQL etc. • Sequence (JPA – SEQUENCE) – Generate identifier with database sequences. • Increment (JPA – Not Supported) – Identifier generation is done at hibernate level rather than DB level. Should not be used much.

Dynamic SQL Generation

• By default, Hibernate creates SQL statements for each persistent class on startup. These statements are simple create, read, update, and delete operations.• Generated SQL statement updates (or inserts) all columns, and if the value of a particular column isn’t modified, the statement sets it to its old value (or null incase of inserts).• You may want to disable it if

• You have large number of columns in a Entity which may affect the performance.• If you have large number of Entities, which will affect the startup time.

<class name="Item" dynamic-insert="true" dynamic-update="true">...</class>

With Annotations:@[email protected]( dynamicInsert = true, dynamicUpdate = true)public class Item { …

Making an entity Immutable

• Advantages of marking an entity as Immutable• Hibernate will avoid dirty checking for the Entity.• Hibernate need not generate queries for Entity update.

• In Java, an class is immutable if it does not provide any public setter methods.• Mapping:

<hibernate-mapping default-access="field"> <class name="Bid" mutable="false"> ... </class></hibernate-mapping>

Annotations:@[email protected](mutable = false)@org.hibernate.annotations.AccessType("field")public class Bid { ...

Property Access Strategies

• Properties of a class are accessed by the persistence engine either directly (through fields) or indirectly (through getter and setter property accessor methods).• In XML mapping files, you control the default access strategy for a class with the default-access="field|property|custom.Class" attribute of the hibernate-mapping root element. • An annotated entity inherits the default from the position of the mandatory @Id annotation.• You can control Access strategy as

<property name="description" column="DESCR" access="field"/>

• or with [email protected](<strategy>)

•Usage : If your database stores the name of a user as a single NAME column, but your User class has firstname and lastname properties, you can add the following persistent name property to the class. In this case you accessor strategy should be property rather than field.

Generated Property Values

• Hibernate applications need to refresh objects that contain any properties for which the database generates values.• Use the generated switch on a property mapping to enable this automatic refresh:

<property name="lastModified“column="LAST_MODIFIED“update="false“insert="false“generated="always"/>

•Whenever Hibernate issues an SQL INSERT or UPDATE for an entity that has defined generated properties, it immediately does a SELECT afterwards to retrieve the generated values.• With Annotations

@Column(updatable = false, insertable = false)@org.hibernate.annotations.Generated( org.hibernate.annotations.GenerationTime.ALWAYS)private Date lastModified;

• The settings available are GenerationTime.ALWAYS and GenerationTime.INSERT and the equivalent options in XML mappings are generated="always" and generated="insert".• Generated properties should be marked as updatable = false and insertable = false, making them readonly.

Default Property Values

• Default values are special types of Generated values. • Hibernate provide a default attribute of the property tag to provide the default value of the field.

<class name="Item" table="ITEM” dynamic-insert="true" dynamic-update="true"> ... <property name="initialPrice" type="big_decimal"> <column name="INITIAL_PRICE" default="'1'" generated="insert"/> </property> ... </class>

•You also have to enable dynamic insertion and update statement generation, so that the column with the default value isn’t included in every statement if its value is null (otherwise a NULL would be inserted instead of the default value). • With Annotations

@Column(name = "INITIAL_PRICE“, columnDefinition = "number(10,2) default '1'")@org.hibernate.annotations.Generated( org.hibernate.annotations.GenerationTime.INSERT)private BigDecimal initalPrice;

Entities and Value Types

• Entities - An object of entity type has its own database identity (primary key value).An object reference to an entity instance is persisted as a reference in the database (a foreign key value). An entity has its own lifecycle; it may exist independently of any other entity.

• Value Types - An object of value type has no database identity; it belongs to an entity instance and its persistent state is embedded in the table row of the owning entity. Value types don’t have identifiers or identifier properties. The lifespan of a value type instance is bounded by the lifespan of the owning entity instance. A value type doesn’t support shared references: If two users live in the same apartment, they each have a reference to their own homeAddress instance. The most obvious value types are classes like Strings and Integers, but all JDK classes are considered value types. User-defined classes can also be mapped as value types.

Mapping Value Types (or Components)• Eg. Relationship

• DB design

Mapping Value Types (or Components)

• XML mapping for the Component<class name="User" table="USER"> ... <component name="homeAddress" class="Address"> <property name="street" type="string" column="HOME_STREET" not-null="true"/> <property name="city" type="string" column="HOME_CITY" not-null="true"/>

<property name="zipcode" type="string" column="HOME_ZIPCODE" not-null="true"/> </component></class>

• Mapping using Annotation@Entity@Table(name = "USERS")public class User { @Embedded private Address homeAddress; }

@Embeddablepublic class Address { @Column(name = "ADDRESS_STREET", nullable = false) private String street; @Column(name = "ADDRESS_ZIPCODE", nullable = false) private String zipcode; @Column(name = "ADDRESS_CITY", nullable = false) private String city;}

Mapping Value Types (or Components)

• Sharing Value object Definitions (classes not references).@AttributeOverrides( { @AttributeOverride(name = "street",

column = @Column(name="HOME_STREET") ), @AttributeOverride(name = "zipcode",

column = @Column(name="HOME_ZIPCODE") ), @AttributeOverride(name = "city",

column = @Column(name="HOME_CITY") )})private Address homeAddress;

• Null handling - Hibernate represents a null component as null values in all mapped columns of the component. This means that if you store a component object with all null property values, Hibernate returns a null component when the owning entity object is retrieved from the database.

Mapping Collection Properties

• Collection Value Types:private <<Interface>> images = new <Implementation>>();// Getter and setter methods

• Mapping a setprivate Set images = new HashSet();

XML:<set name="images" table="ITEM_IMAGE"> <key column="ITEM_ID"/> <element type="string" column="FILENAME" not-null="true"/></set>

Annotations: @org.hibernate.annotations.CollectionOfElements( targetElement = java.lang.String.class)@JoinTable( name = "ITEM_IMAGE", joinColumns = @JoinColumn(name = "ITEM_ID"))@Column(name = "FILENAME", nullable = false)private Set<String> images = new HashSet<String>();

Mapping Collection Properties contd..

• Mapping a bag - An unordered collection that permits duplicate elements is called a bag.

private Collection images = new ArrayList();• XML Mapping

<idbag name="images" table="ITEM_IMAGE"> <collection-id type="long" column="ITEM_IMAGE_ID">

<generator class="sequence"/> </collection-id> <key column="ITEM_ID"/> <element type="string" column="FILENAME" not-null="true"/></idbag>

•Note that the native generator for primary keys isn’t supported for <idbag> mappings; you have to name a concrete strategy.• A surrogate primary key allows duplicate bag elements.

Mapping Collection Properties contd..

• Mapping a list – List will preserve the order of the elements and also allow the duplicate entries.

private List images = new ArrayList();• XML Mapping – List require a position or index column to maintain the order of the elements in db.

<list name="images" table="ITEM_IMAGE"> <key column="ITEM_ID"/> <list-index column="POSITION“ /> <element type="string" column="FILENAME" not-null="true"/></list>

•The primary key of the collection table is a composite of ITEM_ID and POSITION.

@org.hibernate.annotations.CollectionOfElements@JoinTable( name = "ITEM_IMAGE", joinColumns = @JoinColumn(name = "ITEM_ID"))@org.hibernate.annotations.IndexColumn( name="POSITION", base = 1)@Column(name = "FILENAME")private List<String> images = new ArrayList<String>();

Mapping Collection Properties contd..

• Mapping a Map – Map stores objects like key-value pairs.private Map images = new HashMap();

• XML Mapping – <map name="images" table="ITEM_IMAGE"> <key column="ITEM_ID"/> <map-key column="IMAGENAME" type="string"/> <element type="string" column="FILENAME" not-null="true"/></map>

•The primary key of the collection table is a composite of ITEM_ID and IMAGENAME.

@org.hibernate.annotations.CollectionOfElements@JoinTable(name = "ITEM_IMAGE", joinColumns = @JoinColumn(name = "ITEM_ID“))@org.hibernate.annotations.MapKey(columns =

@Column(name="IMAGENAME")) @Column(name = "FILENAME")private Map<String, String> images = new HashMap<String, String>();

Mapping Collection Properties contd..

• Sorted and ordered collections – The difference between Sorted and Ordered collections is sorted collections are sorted in memory using Java comparator, while ordered collections is ordered at the database level (order by clause).• Sorted Map –

private SortedMap images = new TreeMap();• XML Mapping –

<map name="images" table="ITEM_IMAGE" sort="natural"> <key column="ITEM_ID"/> <map-key column="IMAGENAME" type="string"/> <element type="string" column="FILENAME" not-null="true"/></map>

• Specifying a comparator for sortingsort="auction.util.comparator.ReverseStringComparator“>

• Annotations – It’s a set [email protected]@JoinTable( name = "ITEM_IMAGE", joinColumns = @JoinColumn(name = "ITEM_ID"))@Column(name = "FILENAME", nullable = false)@org.hibernate.annotations.Sort( type = org.hibernate.annotations.SortType.NATURAL)private SortedSet<String> images = new TreeSet<String>();

Mapping Collection Properties contd..

• Ordered collections – Ordered collection allow us to use HashMap or HashSet and sort the collection on database side. Hibernate will use LinkedHashSet or LinkedHashMap internally while creating these objects.• XML Mapping –

<map name="images" table="ITEM_IMAGE" order-by="IMAGENAME asc"> <key column="ITEM_ID"/> <map-key column="IMAGENAME" type="string"/> <element type="string" column="FILENAME" not-null="true"/></map>

• Using [email protected]@JoinTable( name = "ITEM_IMAGE", joinColumns = @JoinColumn(name = "ITEM_ID"))@Column(name = "FILENAME", nullable = false)@org.hibernate.annotations.OrderBy( clause = "FILENAME asc")private Set<String> images = new HashSet<String>();

Mapping Collection Properties contd..

• Mapping collection of components – First, implement the Image class as a regular POJO. Component classes don’t have an identifier property. You must implement equals() (and hashCode()). • XML Mapping –

<set name="images” table="ITEM_IMAGE” order-by="IMAGENAME asc"> <key column="ITEM_ID"/> <composite-element class="Image"> <property name="name" column="IMAGENAME" not-

null="true"/> <property name="filename" column="FILENAME" not-null="true"/> <property name="sizeX" column="SIZEX" not-null="true"/> <property name="sizeY" column="SIZEY" not-null="true"/> </composite-element></set>

Mapping Collection Properties contd..

• Primary Key - This is a set, so the primary key of the collection table is a composite of the key column and all element columns. Because these columns all appear in the primary key, you needed to declare them with not-null="true“

• Avoiding Not null columns – A separate primary key is required to avoid not null constrain for all the columns. A bag can be used for that. Note, bag will allow duplicate entries. <idbag name="images" table="ITEM_IMAGE" order-by="IMAGE_NAME asc"> <collection-id type="long" column="ITEM_IMAGE_ID"> <generator class="sequence"/> </collection-id> <key column="ITEM_ID"/> <composite-element class="Image"> <property name="name" column="IMAGENAME"/> <property name="filename" column="FILENAME" not-null="true"/> <property name="sizeX" column="SIZEX"/> <property name="sizeY" column="SIZEY"/> </composite-element> </idbag>

With Annotations – Mark the Image as @Embedable (with column information).

@org.hibernate.annotations.CollectionOfElements@JoinTable ( name = "ITEM_IMAGE", joinColumns = @JoinColumn(name = "ITEM_ID"))private Set<Image> images = new HashSet<Image>();

Entity Associations

• Single-valued entity associations (one to one association)• Shared Primary Key – Rows in two tables related by a primary key association share the same primary key values.

• This needs to be mapped as bidirectional.• Eg. If user Address relationship is mapped as one to one.

public class User {private Address shippingAddress;

}

<one-to-one name="shippingAddress” class="Address”cascade="save-update" />

public class Address {private User user;

}

<class name="Address" table="ADDRESS"><id name="id" column="ADDRESS_ID">

<generator class="foreign"><param

name="property">user</param></generator>

</id><one-to-one name="user“ class="User"

constrained="true“ /></class>

Entity Associations

• Shared Primary Key with Annotations• Define following annotations In User class

@OneToOne@PrimaryKeyJoinColumnprivate Address shippingAddress;

• In Address define the Identifier as follows:

@Entity@Table(name = "ADDRESS")public class Address {

@Id @GeneratedValue(generator = "myForeignGenerator")@org.hibernate.annotations.GenericGenerator(

name = "myForeignGenerator",strategy = "foreign",parameters = @Parameter(name = "property",

value = "user“))@Column(name = "ADDRESS_ID")private Long id;...private User user;

}

Entity Associations

• One-to-one foreign key associations – One to one association can also be mapped using a foreign key.

<class name="User" table="USERS"><many-to-one name="shippingAddress" class="Address"

column="SHIPPING_ADDRESS_ID” cascade="save-update" unique="true" /></class>

With Annotations:public class User {

@OneToOne@JoinColumn(name="SHIPPING_ADDRESS_ID")private Address shippingAddress;

}

One-to-many associations (Many-to-one)

• Example Mapping - One bid is related to one Item, but Item can be related to many Bids. Item contains Bids collection and Bid contains Item’s instance.

<!- Bid Mapping -- ><class name="Bid” table="BID">

<many-to-one name="item” column="ITEM_ID” class="Item” not-null="true“ />

</class>

<!- Item mapping with Bid’s collection as a bag -- ><class name="Item” table="ITEM">

<bag name="bids” inverse="true"><key column="ITEM_ID"/><one-to-many class="Bid"/>

</bag></class>

• Inverse - The inverse attribute tells Hibernate that the collection is a mirror image of the <many-to-one> association on the other side. Note here that we have mapped same foreign key column twice once from both the side, so without the inverse attribute, Hibernate tries to execute two different SQL statements, both updating the same foreign key column, when you manipulate the link between two instances. By specifying inverse="true", you explicitly tell Hibernate which end of the link it should not synchronize with the database.

One-to-many associations (Many-to-one) contd..

• Using Annotations – One to many relationship can be mapped with annotations as follows:

public class Bid { @ManyToOne( targetEntity = auction.model.Item.class ) @JoinColumn(name = "ITEM_ID", nullable = false)

private Item item; }

public class Item { @OneToMany(mappedBy = "item")

private Collection<Bid> bids = new ArrayList<Bid>();}

• The mappedBy attribute is the equivalent of the inverse attribute in XML mappings

One-to-many associations (Many-to-one) contd..

• One-to-many associations using List collections – One-to-many association using List collection is a special case. In case of List, collection mapping contains the information of the indexColumn which need to be persisted. So list collection can not be marked as inverse (ignored for persistent)

public class Item { @OneToMany

@JoinColumn(name = "ITEM_ID", nullable = false) @org.hibernate.annotations.IndexColumn(name =

"BID_POSITION") private List<Bid> bids = new ArrayList<Bid>();}

public class Bid { @ManyToOne @JoinColumn(name = "ITEM_ID", nullable = false, updatable

= false, insertable = false) private Item item;

}• Note no ‘mapped by’ is used in this, also note that ManyToOne relationship is marked as readonly. This infectively reversed the inverse process. • Note : Inverse or (mapped by) are required only in case of bidirectional relationships.

POJOs Associations (Programmatically)

• Object references are bidirectional.• Eg.

public class Category { private String name; private Category parentCategory; private Set childCategories = new HashSet(); ….}

• Adding a child category to a parent category need to be done once for each direction like (better to create a method that will do this). public void addChildCategory(Category childCategory) { if (childCategory == null) throw new IllegalArgumentException("Null child category!"); if (childCategory.getParentCategory() != null) childCategory.getParentCategory().getChildCategories() .remove(childCategory); childCategory.setParentCategory(this); childCategories.add(childCategory); }• These type of methods are required to maintain the right state of the relationship.

Many-to-Many associations• Many to many relationships can be mapped in DB with a third relationship table.

•XML Mapping:<class name="Category" table="CATEGORY"><set name="items" table="CATEGORY_ITEM" cascade="save-update">

<key column="CATEGORY_ID"/><many-to-many class="Item" column="ITEM_ID"/>

</set>

<class name="Item" table="ITEM"><set name="categories" table="CATEGORY_ITEM” inverse="true"

cascade="save-update"><key column="ITEM_ID"/><many-to-many class="Category" column="CATEGORY_ID"/>

</set></class>

Many-to-Many associations

• Using Annotations:

// Category table mapping@ManyToMany@JoinTable(

name = "CATEGORY_ITEM",joinColumns = {@JoinColumn(name = "CATEGORY_ID")},inverseJoinColumns = {@JoinColumn(name = "ITEM_ID")}

)private Set<Item> items = new HashSet<Item>();

// Item table mapping.@ManyToMany(mappedBy = "items")private Set<Category> categories = new HashSet<Category>();

Many-to-Many associations

• Join tables with additional columns - In a real system, you may not have a many-to-many association. It happens that there is almost always other information that must be attached to each link between associated instances and that the best way to represent this information is via an intermediate association class.

• Create a CategoriedItem class having two many to one relationships to Category and Item.

Mapping a Parent/Children relationship

• Simple bidirectional XML Mapping – <class name="Item" table="ITEM">

<set name="bids" inverse="true"><key column="ITEM_ID"/><one-to-many class="Bid"/>

</set></class><class name="Bid" table="BID">

<many-to-one name="item" column="ITEM_ID" class="Item" not-null="true"/>

</class>Annotations:

@OneToMany(mappedBy = "item")private Set<Bid> bids = new HashSet<Bid>();

@ManyToOne( targetEntity = auction.model.Item.class )@JoinColumn(name = "ITEM_ID", nullable = false)private Item item;

Mapping a Parent/Children relationship contd..

• Consider following code:Item newItem = new Item();Bid newBid = new Bid();newItem.addBid(newBid); // Set both sides of the associationsession.save(newItem);session.save(newBid);

• Transitive persistence <set name="bids” inverse="true” cascade="save-update">

<key column="ITEM_ID"/><one-to-many class="Bid"/>

</set>

•Cascade - The cascade attribute is directional: It applies to only one end of the association.

public class Item {@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE},mappedBy = "item")private Set<Bid> bids = new HashSet<Bid>();

}

Mapping a Parent/Children relationship contd..

• What about delete? – In case of Parent Children relationship, it is expected that if we delete the parent child should gets deleted. So It seems reasonable that deletion of an item implies deletion of all bids for the item.• Manually deleting the Bids before deleting the Item:

Item anItem = // Load an item// Delete all the referenced bidsfor ( Iterator<Bid> it = anItem.getBids().iterator();it.hasNext(); ) {

Bid bid = it.next();it.remove(); // Remove reference from collectionsession.delete(bid); // Delete it from the database

}session.delete(anItem); // Finally, delete the item

• Using cascade delete<set name="bids" inverse="true" cascade="save-update, delete">.. </set>

@OneToMany(cascade = { CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE },mappedBy = "item")private Set<Bid> bids = new HashSet<Bid>();

Item anItem = // Load an itemsession.delete(anItem);

Mapping a Parent/Children relationship contd..

• What about shared references? – You may have shared references to the Bid objects. A User may have a collection of references to the Bid instances they made.

• Manually chasing the pointer:Item anItem = // Load an item// Delete all the referenced bids

for ( Iterator<Bid> it = anItem.getBids().iterator(); it.hasNext(); ) { Bid bid = it.next();// Remove references from users who have made this bid

Query q = session.createQuery("from User u where :bid in elements(u.bids)");q.setParameter("bid", bid);Collection usersWithThisBid = q.list();

for (Iterator itUsers = usersWithThisBid.iterator(); itUsers.hasNext();) {User user = (User) itUsers.next();user.getBids().remove(bid);}

} session.delete(anItem);

Mapping a Parent/Children relationship contd..

• What about shared references? – You may have shared references to the Bid objects. A User may have a collection of references to the Bid instances they made.

• Manually chasing the pointer:Item anItem = // Load an item// Delete all the referenced bids

for ( Iterator<Bid> it = anItem.getBids().iterator(); it.hasNext(); ) { Bid bid = it.next();// Remove references from users who have made this bid

Query q = session.createQuery("from User u where :bid in elements(u.bids)");q.setParameter("bid", bid);Collection usersWithThisBid = q.list();

for (Iterator itUsers = usersWithThisBid.iterator(); itUsers.hasNext();) {User user = (User) itUsers.next();user.getBids().remove(bid);}

} session.delete(anItem);

Mapping a Parent/Children relationship contd..

© Nihilent Technologies 2011

• What about de-referenced collection elements? – Earlier we save the issue of delete of children(Bids) when we were trying to delete the parent (Item). But what about this code, anItem.getBids().remove(aBid). Logically it should delete the Bid which does not belong to any Item. But the bid may have other references. • Hibernate provides a cascade option, to delete such a child if there is no other entity, referencing to child entity. Its called as delete-orphan

<set name="bids" inverse="true" cascade="save-update, delete, delete-orphan">

Annotations:@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE }, mappedBy = "item")

@org.hibernate.annotations.Cascade ( value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN )

private Set<Bid> bids = new HashSet<Bid>();

Mapping a Parent/Children relationship contd..

© Nihilent Technologies 2011

• Summary of Relationship• If a parent is passed to save(), update() or saveOrUpdate(), all children are passed to saveOrUpdate() – Achieved through cascade =‘save-update’

• If a transient or detached child becomes referenced by a persistent parent, it is passed to saveOrUpdate() – Achieved through cascade=‘save-update’

• If a parent is deleted, all children are passed to delete() – Achieved through cascade = ‘delete’ and manually removing the shared references.

•If a child is dereferenced by a persistent parent, child should get deleted – Achieved through cascade="delete-orphan", if there are no shared references.

Mapping a Inheritance

© Nihilent Technologies 2011

• Table per concrete class with implicit polymorphism

•The mapping for CreditCard and BankAccount is straightforward. Map each in its own entity <class> element without a superclass. Hibernate will still know about the superclass.• The main problem with this approach is that it doesn’t support polymorphic associations very well.• Polymorphic queries (queries that return objects of all classes that match the interface of the queried class) are also problematic. A query against the superclass must be executed as several SQL SELECTs, one for each concrete subclass.•A further conceptual problem with this mapping strategy is that several different columns, of different tables, share exactly the same semantics. This makes schema evolution more complex.

Mapping a Inheritance

© Nihilent Technologies 2011

• Table per concrete class with implicit polymorphism@MappedSuperclasspublic abstract class BillingDetails {

@Column(name = "OWNER", nullable = false)private String owner;

}

@Entity@AttributeOverride(name = "owner", column = @Column(name = "CC_OWNER", nullable = false))public class CreditCard extends BillingDetails {

@Id @GeneratedValue@Column(name = "CREDIT_CARD_ID")private Long id = null;

@Column(name = "NUMBER", nullable = false)private String number;

}

Mapping a Inheritance

© Nihilent Technologies 2011

• Table per concrete class with unions• As in the previous section. In this situation, we again have two tables and duplicate superclass columns in both: CREDIT_CARD and BANK_ACCOUNT. What’s new is a special Hibernate mapping that includes the superclass.

<hibernate-mapping><class name="BillingDetails" abstract="true">

<id name="id" column="BILLING_DETAILS_ID" type="long"><generator class="native"/>

</id><property name="name" column="OWNER" type="string"/>

<union-subclass name="CreditCard" table="CREDIT_CARD"><property name="number" column=”NUMBER”/><property name="expMonth" column="EXP_MONTH"/><property name="expYear" column="EXP_YEAR"/>

</union-subclass></class>

</hibernate-mapping>

•The first advantage you may notice with this strategy is the shared declaration of superclass (or interface) properties.

Mapping a Inheritance

• Table per concrete class with unions• In JPA annotations, this strategy is known as TABLE_PER_CLASS.

@Entity@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)public abstract class BillingDetails {

@Id @GeneratedValue@Column(name = "BILLING_DETAILS_ID")private Long id = null;

@Column(name = "OWNER", nullable = false)private String owner;

}

@Entity@Table(name = "CREDIT_CARD")public class CreditCard extends BillingDetails {

@Column(name = "NUMBER", nullable = false)private String number;

}

Mapping a Inheritance

• Table per concrete class with unions• The advantages of this mapping strategy are we have one single polymorphic queries with union.• (Query provided for reference only).select

BILLING_DETAILS_ID, OWNER,NUMBER, EXP_MONTH, EXP_YEAR, ACCOUNT, BANKNAME, SWIFT,

CLAZZ_from( select

BILLING_DETAILS_ID, OWNER, NUMBER, EXP_MONTH, EXP_YEAR, null as ACCOUNT, null as BANKNAME, null as SWIFT,

1 as CLAZZ_ from CREDIT_CARD union

selectBILLING_DETAILS_ID, OWNER,null as NUMBER, null as

EXP_MONTH, null as EXP_YEAR, ...ACCOUNT, BANKNAME, SWIFT,2 as CLAZZ_

from BANK_ACCOUNT)

Mapping a Inheritance

• Table per class hierarchy• An entire class hierarchy can be mapped to a single table. This table includes columns for all properties of all classes in the hierarchy. The concrete subclass represented by a particular row is identified by the value of a type discriminator column.

• This mapping strategy is a winner in terms of both performance and simplicity. It’s the best-performing way to represent polymorphism—both polymorphic and nonpolymorphic queries perform well—and it’s even easy to implement by hand. Ad-hoc reporting is possible without complex joins or unions. • Columns for properties declared by subclasses must be declared to be nullable. If your subclasses each define several nonnullable properties, the loss of NOT NULL constraints may be a serious problem from the point of view of data integrity.

Mapping a Inheritance

© Nihilent Technologies 2011

• Table per class hierarchy• XML Mapping

<hibernate-mapping><class name="BillingDetails" table="BILLING_DETAILS"><id name="id" column="BILLING_DETAILS_ID" type="long">

<generator class="native"/></id><discriminator column="BILLING_DETAILS_TYPE" type="string"/><property name="owner" column="OWNER" type="string"/><subclass name="CreditCard" discriminator-value="CC">

<property name="number" column="CC_NUMBER"/><property name="expMonth"

column="CC_EXP_MONTH"/><property name="expYear" column="CC_EXP_YEAR"/>

</subclass><subclass name=”BankAccount” discriminator-value=”BA”>...</class>

</hibernate-mapping>

Mapping a Inheritance

© Nihilent Technologies 2011

• Table per class hierarchy• This mapping strategy is also available in JPA, as SINGLE_TABLE:• Annotations

@Entity@Inheritance(strategy = InheritanceType.SINGLE_TABLE)@DiscriminatorColumn( name = "BILLING_DETAILS_TYPE", discriminatorType = DiscriminatorType.STRING )public abstract class BillingDetails {

@Id @GeneratedValue@Column(name = "BILLING_DETAILS_ID")private Long id = null;

@Column(name = "OWNER", nullable = false)private String owner;

}

@Entity@DiscriminatorValue("CC")public class CreditCard extends BillingDetails {

@Column(name = "CC_NUMBER")private String number;

}

Mapping a Inheritance

• Table per subclass Every class/subclass that declares persistent properties—including abstract classes and even interfaces—has its own table.

Mapping a Inheritance

• Table per subclass• The primary key columns share the primary key value with superclass table.• The primary advantage of this strategy is that the SQL schema is normalized. Schema evolution and integrity constraint definition are straightforward. A polymorphic association to a particular subclass may be represented as a foreign key referencing the table of that particular subclass.

<hibernate-mapping><class name="BillingDetails" table="BILLING_DETAILS">

<id name="id" column="BILLING_DETAILS_ID" type="long"><generator class="native"/>

</id><property name="owner" column="OWNER" type="string"/><joined-subclass name="CreditCard" table="CREDIT_CARD">

<key column="CREDIT_CARD_ID"/><property name="number" column="NUMBER"/><property name="expMonth" column="EXP_MONTH"/><property name="expYear" column="EXP_YEAR"/>

</joined-subclass><joined-subclass name="BankAccount"

table="BANK_ACCOUNT"> ... </class>

</hibernate-mapping>

Mapping a Inheritance

• Table per subclass• Polymorphic query fired will be something like this (query given only for reference)

select BD.BILLING_DETAILS_ID, BD.OWNER,CC.NUMBER, CC.EXP_MONTH, ..., BA.ACCOUNT, BA.BANKNAME, ...case

when CC.CREDIT_CARD_ID is not null then 1when BA.BANK_ACCOUNT_ID is not null then 2when BD.BILLING_DETAILS_ID is not null then 0

end as CLAZZ_from BILLING_DETAILS BD left join CREDIT_CARD CC on BD.BILLING_DETAILS_ID = CC.CREDIT_CARD_IDleft join BANK_ACCOUNT BA on BD.BILLING_DETAILS_ID = BA.BANK_ACCOUNT_ID

• As you can see, this mapping strategy is more difficult to implement by hand, even ad-hoc reporting is more complex.• Queries always require either a join across many tables or many sequential reads.

Mapping a Inheritance

• Table per subclass• Use Annotations

@Entity@Inheritance(strategy = InheritanceType.JOINED)public abstract class BillingDetails {

@Id @GeneratedValue@Column(name = "BILLING_DETAILS_ID")private Long id = null;

}

@Entitypublic class BankAccount { ... }

• If you have different primary key column

@Entity@PrimaryKeyJoinColumn(name = "CREDIT_CARD_ID")public class CreditCard {...}

Mapping a Inheritance

• Mixing inheritance strategies• 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 <join> mapping element

<hibernate-mapping><class name="BillingDetails" table="BILLING_DETAILS">

<discriminator column="BILLING_DETAILS_TYPE" type="string"/><subclass name="CreditCard" discriminator-value="CC"> <join table="CREDIT_CARD"> <key column="CREDIT_CARD_ID"/> <property name="number" column="CC_NUMBER"/> <property name="expMonth" column="CC_EXP_MONTH"/> <property name="expYear" column="CC_EXP_YEAR"/> </join></subclass><subclass name="BankAccount" discriminator-value="BA">

<property name=account" column="BA_ACCOUNT"/></subclass>

</class></hibernate-mapping>

Mapping a Inheritance

• Mixing inheritance strategies

•Annotations@Entity@DiscriminatorValue("CC")@SecondaryTable(name = "CREDIT_CARD", pkJoinColumns = @PrimaryKeyJoinColumn(name = "CREDIT_CARD_ID"))public class CreditCard extends BillingDetails {

@Column(table = "CREDIT_CARD", name = "CC_NUMBER", nullable = false) private String number;}

Mapping a Inheritance

• Choosing a strategy• If you don’t require polymorphic associations or queries, lean toward table-per-concrete-class—in other words, if you never or rarely query for BillingDetails and you have no class that has an association to BillingDetails (our model has). An explicit UNION-based mapping should be preferred, because (optimized) polymorphic queries and associations will then be possible later.

• If you do require polymorphic associations (an association to a superclass, hence to all classes in the hierarchy with dynamic resolution of the concrete class at runtime) or queries, and subclasses declare relatively few properties (particularly if the main difference between subclasses is in their behavior), lean toward table-per-class-hierarchy.

• If you do require polymorphic associations or queries, and subclasses declare many properties (subclasses differ mainly by the data they hold), lean toward table-per-subclass.

• If only one or two subclasses holds the different property you can even use the mix approach.

• In case of polymorphic association or queries, your second option is to use table-per-concrete-class if the cost of the joins or more than cost of union.

The persistence lifecycle

The persistence context

• You may consider the persistence context to be a cache of managed entity instances.

• In a Hibernate application, one Session has one internal persistence context.

• The persistence context is useful for several reasons: • Hibernate can do automatic dirty checking and transactional write-behind.• Hibernate can use the persistence context as a first-level cache.• Hibernate can guarantee a scope of Java object identity.• Hibernate can extend the persistence context to span a whole conversation.

• Automatic Dirty checking - Hibernate compares an old snapshot of an object with the snapshot at synchronization time, and it detects any modifications that require an update of the database state.

• Persistence context cache - This means it remembers all persistent entity instances you’ve handled in a particular unit of work. If Hibernate is told to load an object by primary key (a lookup by identifier), it can first check the persistence context for the current unit of work. If the entity is found there, no database hit occurs. Persistence context cache is always on and can’t be turned off.

Scope of Object Identity

• A persistence layer using persistence context-scoped identity guarantees that, in the scope of a single persistence context, only one object instance represents a particular database row.• This avoids conflicting representations of the same database row at the end of a unit of work.

Session session1 = sessionFactory.openSession();Transaction tx1 = session1.beginTransaction();

// Load Item with identifier value "1234"Object a = session1.get(Item.class, new Long(1234) );Object b = session1.get(Item.class, new Long(1234) );( a==b ) // True, persistent a and b are identical

tx1.commit();session1.close();

// References a and b are now to an object in detached stateSession session2 = sessionFactory.openSession();Transaction tx2 = session2.beginTransaction();

Object c = session2.get(Item.class, new Long(1234) );( a==c ) // False, detached a and persistent c are not identicaltx2.commit();session2.close();

Implementing equals() and Hashcode()

• You can implement the equals using the identifier properties, but it will be problematic for transient objects so no identifier property will be assigned.

• Alternatively, you can use all the values of the fields in the Entity to implement the equals(). But it may happen if user modifies value of a field then two same rows are not same. Another problem is, Instances with different database identity (instances that represent different rows of the database table) can be considered equal unless some combination of properties is guaranteed to be unique.• Implementing equality with a business key - A business key is a property, or some combination of properties, that is unique for each instance with the same database identity. Essentially, it’s the natural key that you would use if you weren’t using a surrogate primary key instead.

public class User { public boolean equals(Object other) {

if (this==other) return true; if ( !(other instanceof User) ) return false; final User that = (User) other; return this.username.equals( that.getUsername() ); }

public int hashCode() { return username.hashCode(); }}

• Also note that equals needs to call accessor methods on another instance because it might be a proxy.

Hibernate Interfaces

• Beginning a unit of workSession session = sessionFactory.openSession();Transaction tx = session.beginTransaction();

• Making an object persistentItem item = new Item(); session.save(item);

• Retrieving a persistent objectItem item = (Item) session.load(Item.class, new Long(1234)); // may return a proxyItem item = (Item) session.get(Item.class, new Long(1234)); // alsways hit the db.

• Modifying a persistent objectItem item = (Item) session.get(Item.class, new Long(1234));

• Reattaching a modified detached instancesessionTwo.update(item); // a update query is scheduled here. item.setEndDate(...);tx.commit();

• Making a detached object transientsession.delete(item); // item will be attached to the session before deletion can happen.

• Merging the state of a detached object – Update will throw an exception if your current persistent context hold the same entity instance.

Item item2 = (Item) session.get(Item.class, new Long(1234));Item item3 = (Item) session.merge(item);(item == item2) // False(item == item3) // False(item2 == item3) // True

• Merge done a implicit get if no instance is found in the current persistent context. If none found in the db then insertion will be done at the end of the transaction. • Merging includes all value-typed properties and all additions and removals of elements to any collection.

Hibernate Interfaces

• Managing persistent context – Hibernate manages the persistent object in a persistent context. Hibernate maintain a snapshot of every persistent object for automatic dirty checking. This may lead to OutOfMemory exception if large number of objects are retrieved into the session, majority of which will not be modified. • Detach the persistent object from Session – Hibernate will not maintain the snapshots of the Detached objects

session.evict(object) ;• Mark the object read only – This will also lead to deletion of the snapshot from the memory, since hibernate need not manage the readonly object for dirty check.

Session.setReadOnly(object, true)

• Flushing the persistent context – Synchronization of a persistent context with the database is called flushing.

Fetching strategies

• Hibernate defaults to a lazy fetching strategy for all entities and collections.• Proxies - Proxies are placeholders that are generated at runtime.

Item item = (Item) session.load(Item.class, new Long(123));item.getId(); // initialisation of the proxy if access strategy is field.item.getDescription(); // Initialize the proxy if access strategy is property.

• A collection is initialized if you start iterating through its elements or if you call any of the collection- management operations, such as size() and contains().• For collection Hibernate provides a feature as lazy=“extra”.

<set name="bids” lazy="extra” inverse="true"> <key column="ITEM_ID"/> <one-to-many class="Bid"/> </set>@[email protected]( org.hibernate.annotations.LazyCollectionOption.EXTRA)private Set<Bid> bids = new HashSet<Bid>();

Fetching strategies

• You can disable proxy generation for a particular entity class with the lazy="false" attribute in XML mapping metadata:

<class name="User" table="USERS" lazy="false">• Instead of using lazy=false at class level, you can use it as property or collection level to fetch the property or collection eagerly.

@ManyToOne(fetch = FetchType.EAGER)private User seller;

• Although all associations in Hibernate are completely lazy, all @ManyToOne and @OneToOne associations default to FetchType.EAGER. This restriction is due to JPA specification.• Fetching Strategies • Prefetching data in batches – Can be declared at collection level too.

<class name="User” table="USERS” batch-size="10“>@org.hibernate.annotations.BatchSize(size = 10)

• Prefetching collections with subselects - Hibernate now initializes all bids collections for all loaded Item objects, as soon as you force the initialization of one bids collection.

<set name="bids” inverse="true” fetch="subselect">• Eager fetching with joins

<set name="bids" inverse="true" fetch="join">

HQL

• Named Queries@NamedQueries({@NamedQuery( name = "findItemsByDescription", query = "select i from Item i where i.description like :desc")})

• Implicit Joinsfrom User u where u.homeAddress.city = 'Bangkok‘

• Joins in from clausedfrom Item i join i.bids b where i.description like '%Foo%' and b.amount > 100

• Dynamic fetching strategyfrom Item i left join fetch i.bids where i.description like '%Foo%‘

• Comparing Identifiersfrom Item i, User u where i.seller = u and u.username = 'steve‘

• Utilizing dynamic instantiationselect new ItemBidSummary(bid.item.id, count(bid), avg(bid.amount))from Bid bidwhere bid.item.successfulBid is nullgroup by bid.item.id

Thank you