Free Online Courses for Software Developers - MrBool
× Please, log in to give us a feedback. Click here to login
×

You must be logged to download. Click here to login

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

Hibernate Framework: OrphanRemoval with Hibernate

See in this article how the orphanRemoval attribute works, present in most annotations of relationships between entities, and used to define how a removal action is assigned to an object.

Among all the features that Hibernate provides maybe one of the fastest draw the attention of the developers is the removal of values, motivated mainly by the great importance and impact that it generates in an application, given the relevance of the information (the data handled) has to the same.

Therefore, this article aims to achieve exactly this gap that many developers have regarding the use of the mechanisms that the ORM framework has to perform the deletion of values from the database, via famous annotations. Among these same mechanisms, we can highlight the role of the attribute "orphanRemoval", present in most relationships between entities notes, and used to define how a removal action assigned to an object will impact the related objects.

To this end, we will make the creation of a sample project using the Java technologies, Spring and Hibernate (all in their latest versions).

Configuring and creating the project

Initially, download all dependencies that the project will need to function properly (Listing 1). Consider using the Eclipse IDE (also in its latest version) for the same.

The same list can be downloaded through the option of download link of this project above the article. Note that Listing 1 shows the list without the libs in specific version to use this because you can always use the most recent references of the same, or even set up your project to use a maven repository, for example.

Listing 1. List of jars required for the project in question

org.springframework.aop-xxx.RELEASE.jar 
org.springframework.asm-xxx.RELEASE.jar 
org.springframework.aspects-xxx.RELEASE.jar
 org.springframework.beans-xxx.RELEASE.jar 
org.springframework.context.support-xxx.RELEASE.jar
 org.springframework.context-xxx.RELEASE.jar
 org.springframework.core-xxx.RELEASE.jar 
org.springframework.jdbc-xxx.RELEASE.jar 
org.springframework.orm-xxx.RELEASE.jar 
org.springframework.transaction-xxx.RELEASE.jar. 
org.springframework.expression-xxx.RELEASE.jar 
commons-logging-xxx.jar 
log4j.jar
 aopalliance-xxx.jar 
dom4j-xxx.jar 
hibernate-commons-annotations-xxx.Final.jar 
hibernate-core-xxx.Final.jar 
hibernate-jpa-2.0-api-xxx.Final.jar
 javax.persistence-xxx.jar
 jta-xxx.jar
 javassist-xxx.jar 
slf4j-api-xxx.jar
 mysql-connector-java-xxx-bin.jar 
commons-collections-xxx.jar

Imagine the following scenario: We have a basic CRUD application that was all set to save cross-data of two simple entities: Person and Address. Both entities are related through a Many-to-Many relationship via Hibernate annotations in model and using the technologies listed yet.

An experienced developer in Hibernate ORM would be ready to make the system and deal with the persistence layer using Hibernate itself. For simplicity, it will be using a stand alone application to continue the information of people. Then see how the division of tasks will be made for that model in particular:

  • Drawing data model (tables);
  • Domain classes and Hibernate mappings;
  • DAO Classes & Service;
  • Spring configuration for the application;
  • A simple main class to show how everything works.

Template design

The database design is relatively simple, containing only three simple tables with a many-to-many relationship as mentioned above and shown in Figure 1.

Data model for the example developed

Figure 1. Data model for the example developed.

As is the reader's knowledge, the intermediate table will serve as support for saving all cross information between the two main entities. It will also be extremely important to demonstrate the good use of orphanRemoval attribute.

Domain classes and Hibernate mapping

The first work to be done programmatically is to create and map the entities, mapping them properly according to the Hibernate annotations. Recalling that will not be focus of this article treat concepts related to the purpose of each note or how to use them. It is assumed that the reader already has such knowledge.

Create the first entity within a package called "br.com.mrbool.hibernate.removal_example" and add to it the code of Listing 2.

Listing 2. Entity Person mapped in Hibernate

package br.com.mrbool.hibernate.removal_example;
   
  import java.io.Serializable;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.List;
  import javax.persistence.CascadeType;
  import javax.persistence.Column;
  import javax.persistence.Entity;
  import javax.persistence.FetchType;
  import javax.persistence.GeneratedValue;
  import javax.persistence.GenerationType;
  import javax.persistence.Id;
  import javax.persistence.JoinColumn;
  import javax.persistence.JoinTable;
  import javax.persistence.OneToMany;
  import javax.persistence.Table;
   
  @Entity
  @Table(name = "Person")
  public class Person implements Serializable {
   
       /**
        * Serial Version UID
        */
       private static final long serialVersionUID = -4221733194426887403L;
   
       @Id
       @GeneratedValue(strategy = GenerationType.AUTO)
       @Column(name = "idPerson")
       private Long idPerson;
   
       @Column(name = "name")
       private String name;
   
       @Column(name = "age")
       private Integer age;
   
       @Column(name = "date_of_birth")
       private Date dtBirth;
       
       @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, orphanRemoval = true)
       @JoinTable(name = "PersonAddress", 
            joinColumns = { @JoinColumn(name = "idPerson") }, 
               inverseJoinColumns = { @JoinColumn(name = "idAddress") }) 
)
       private List<Address> listAddresss = new ArrayList<Address>(0);
   
       /**
        * @return the idPerson
        */
       public Long getIdPerson() {
            return idPerson;
       }
   
       /**
        * @param idPerson
        *            the idPerson to be set
        */
       public void setIdPerson(Long idPerson) {
            this.idPerson = idPerson;
       }
   
       /**
        * @return the name
        */
       public String getName() {
            return name;
       }
   
       /**
        * @param name
        *            the name to be set
        */
       public void setName(String name) {
            this.name = name;
       }
   
       /**
        * @return the age
        */
       public Integer getIdade() {
            return age;
       }
   
       /**
        * @param age
        *            the age to be set
        */
       public void setIdade(Integer age) {
            this.age = age;
       }
   
       /**
        * @return the dtBirth
        */
       public Date getDtBirth() {
            return dtBirth;
       }
   
       /**
        * @param dtBirth
        *            the dtBirth to be set
        */
       public void setDtBirth(Date dtBirth) {
            this.dtBirth = dtBirth;
       }
   
       
       /**
        * @return the listAddresss
        */
       public List<Address> getListAddresss() {
            return listAddresss;
       }
   
       
       /**
        * @param listAddresss the listAddresss to be set
        */
       public void setListAddresss(List<Address> listAddresss) {
            this.listAddresss = listAddresss;
       }
  }

Since we are using MySQL as the primary database, we chose GeneratedValue strategy as GenerationType.AUTO that will do the auto-increment whenever a new person and/or address are created. All other mappings are familiar.

Be aware also of the correct mappings for @Column annotation, since it will define the correct value of the column in the database. Therefore, if you are using your own settings take care when you map them.

Soon after, do the same procedure now for the Address entity. Create a new class in the same package and enter the same code on the Listing 3.

Listing 3. Mapping code for Address entity

package br.com.mrbool.hibernate.removal_example;
   
  import java.io.Serializable;
  import javax.persistence.Column;
  import javax.persistence.Entity;
  import javax.persistence.GeneratedValue;
  import javax.persistence.GenerationType;
  import javax.persistence.Id;
  import javax.persistence.Table;
   
  @Entity
  @Table(name = "Address")
  public class Address implements Serializable {
   
       /**
        * Serial Version UID
        */
       private static final long serialVersionUID = -1314843665707276799L;
   
       @Id
       @GeneratedValue(strategy = GenerationType.AUTO)
       @Column(name = "idAddress")
       private Long idAddress;
   
       @Column(name = "street")
       private String street;
   
       @Column(name = "number")
       private Integer number;
   
       @Column(name = "zip")
       private Integer zip;
   
       /**
        * @return the idAddress
        */
       public Long getIdAddress() {
            return idAddress;
       }
   
       /**
        * @param idAddress
        *            the idAddress to be set
        */
       public void setIdAddress(Long idAddress) {
            this.idAddress = idAddress;
       }
   
       /**
        * @return the street
        */
       public String getStreet() {
            return street;
       }
   
       /**
        * @param street
        *            the street to be set
        */
       public void setStreet(String street) {
            this.street = street;
       }
   
       /**
        * @return the number
        */
       public Integer getNumero() {
            return number;
       }
   
       /**
        * @param number
        *            the number to be set
        */
       public void setNumero(Integer number) {
            this.number = number;
       }
   
       /**
        * @return the zip
        */
       public Integer getCep() {
            return zip;
       }
   
       /**
        * @param zip
        *            the zip to be set
        */
       public void setCep(Integer zip) {
            this.zip = zip;
       }
   
  }

The important fact to note here is the annotation OneToMany (cascade = {} CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true). Here we set the property orphanRemoval = true.

And what does it do exactly? Say you have a group of people registered on the base. And they say that a superhero goes wrong. And then we need to remove one of these people the same. With simple settings Cascade JPA that is not possible, since they do not detect child records and you would have to end the database by deleting them as your collection still had a reference to any of them.

Before JPA 2.0 you would not have support orphanRemoval and the only way to delete orphaned records (children) would be to use the specific Hibernate annotation below, which is now obsolete, by the way:

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

Now we have made this whole process, let's see how is all part of bank and business classes.

Business classes and DAO

To keep the good design patterns we separate the DAO layer (Data Access Object) service layer. For this, we need a DAO interface and its implementation. Note that we are using HibernateTemplate through HibernateDaoSupport in order to keep away from any specific Hibernate details and access everything in a unified manner using Spring.

Then see in Listings 4 and 5 the code needed to configure the interface and implementation class of our DAO, with two very basic operations: creating or updating an entity Person and a recovery method of the same.

Listing 4. Code of creation of PersonDAO interface

package br.com.mrbool.hibernate.dao;
   
  import org.springframework.transaction.annotation.Propagation;
  import org.springframework.transaction.annotation.Transactional;
  import br.com.mrbool.hibernate.removal_example.Person;
   
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
  public interface PersonDAO {
   
       public void createOrUpdatePerson(Person person);
   
       public Person getPersonById(Long id);
  }

Listing 5. Code of implementing class of PersonDAO

package br.com.mrbool.hibernate.dao;
   
  import org.springframework.beans.factory.annotation.Qualifier;
  import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
  import org.springframework.transaction.annotation.Propagation;
  import org.springframework.transaction.annotation.Transactional;
   
  import br.com.mrbool.hibernate.removal_example.Person;
   
  @Qualifier(value="personHibernateDAO")
  public class PersonHibernateDAOImpl extends HibernateDaoSupport implements PersonDAO {
   
       @Override
       public void createOrUpdatePerson(Person person) {
            if (person.getIdPerson() == null) {
                  getHibernateTemplate().persist(person);
            } else {
                  getHibernateTemplate().update(person);
            }
       }
       
       @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = false)  
       public Person getPersonById(Long id){
            return getHibernateTemplate().get(Person.class, id);
       }
  }

Note that is in the interface layer where we define the processing of transactions, as required. This is done because whenever you do not need a transaction you can set this in the specific method level, therefore in most situations you will need a transaction with the exception of data recovery methods.

In Listing 5 we define the @Qualifier to let Spring know that this is the Hibernate implementation of the DAO class. This in my view is a good concept design to track where you separate its implementation in separate packages to maintain the clean design.

Also note that the entire implementation of both resources occurs quickly and fully integrated into the functionality of resources used, making use of all the power that annotatioms provide.

Okay, let's move on to the implementation of the service layer. The service layer, in this case is just acting as a mediation layer to call the DAO methods. But in a real application, you will probably have other validations, security-related procedures etc. treated in the service layer. Get the code now ofListings 6 and 7.

Listing 6. Code to create the service interface

package br.com.mrbool.service;
   
  import br.com.mrbool.hibernate.removal_example.Person;
   
  public interface PersonService {
   
       public void handlePersonCriateUpdate(Person pessoa);
   
       public Person getPersonById(Long id);
   
  }

Listing 7. Implementation code of the service class

package br.com.mrbool.service.impl;
   
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.beans.factory.annotation.Qualifier;
  import org.springframework.stereotype.Component;
  import br.com.mrbool.hibernate.dao.PersonDAO;
  import br.com.mrbool.hibernate.removal_example.Person;
  import br.com.mrbool.service.PersonService;
   
  @Component("personService")
  public class PersonServiceImpl implements PersonService {
   
       @Autowired
       @Qualifier(value = "personHibernateDAO")
       private PersonDAO personDAO;
   
       @Override
       public void handlePersonCreateUpdate(Person person) {
            personDAO.createOrUpdatePerson(person);
       }
   
       public Person getPersonById(Long id) {
            return personDAO.getPersonById(id);
       }
  }

This implementation also dispenses many comments. First, the @Component league this service implementation with the name personService within the Spring context so that we can refer to the bean as a bean with an id of personService name.

Also, see that we have taken a autowired in personDAO and define a @Qualifier so it is bound to the implementation of Hibernate.

The value of the qualifier must be the same name we gave in Qualifier class level within the DAOImpl class. Finally, check out the Spring configuration that makes a wire in all these together. See then in Listing 8 the presence of the default setting for the Spring, in relation to its spring-context.xml.

Listing 8. Setting the spring-context.xml

<context:component-scan base-package="br.com.mrbool" >
  <context:annotation-config >
   
  <tx:annotation-driven >
   
  <bean id="sessionFactory"
   class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
       <property name="packagesToScan">
            <list>
                  <value>br.com.mrbool.**.*</value>
            </list>
       </property>
       <property name="hibernateProperties">
            <props>
                  <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                  <prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
                  <prop key="hibernate.connection.url">jdbc:mysql://localhost:3306/mrbool_test_removal</prop>
                  <prop key="hibernate.connection.username">root</prop>
                  <prop key="hibernate.connection.password">your_pass</prop>
                  <prop key="hibernate.show_sql">true</prop>
                  <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
   
            </props>
       </property>
  </bean>
   
  <bean id="personDAO"
       class="br.com.mrbool.hibernate.dao.PersonDAOImpl">
       <property name="sessionFactory" ref="sessionFactory" >
  </bean>
   
  <bean id="transactionManager"
       class="org.springframework.orm.hibernate3.HibernateTransactionManager">
       <property name="sessionFactory" ref="sessionFactory" >
  </bean>

Note that here we hide the details of the XML file header creation to simplify the listing. On the same table we are using HibernateTransactionManager as an instance to run the example in stand alone. If you are running the same example in a server application you need to use the JTA transaction manager.

We are also using the self-creation feature of the tables in the database using Hibernate (standard feature) to simplify implementation. The property "packaagesToScan" tells you how to scan all subpackages within the application root package, in this case the annotated classes withEntity specifically.

Finally, it is also possible to observe the association between the session factory to PersonDao in particular, which allows us to work with Hibernate Template.

Now that everything is almost set, we have to create the objects themselves to check the operation of all this programming.

Then create a new test class called TestesHibernate, with the main method created for testing purpose. And add in this same code in Listing 9.

Listing 9. Test Class

package br.com.mrbool.teste;
   
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.List;
  import org.springframework.context.ApplicationContext;
  import org.springframework.context.support.ClassPathXmlApplicationContext;
  import br.com.mrbool.hibernate.removal_example.Address;
  import br.com.mrbool.hibernate.removal_example.Person;
  import br.com.mrbool.service.PersonService;
   
  public class TestHibernate {
   
       /**
        * @param args
        */
       public static void main(String[] args) {
   
            ApplicationContext ctx =
                       new ClassPathXmlApplicationContext("spring-context.xml");
            PersonService service =
                       (PersonService) ctx.getBean("personService");
   
            Person person = new Person();
            List<Address> addresses = getAddresss();
   
            person.setListAddresss(addresses);
            person.setDtNasc(new Date());
            person.setIdade(30);
            person.setNome("Devmedia");
   
            service.handlePersonCriarAtualizar(person);
   
       }
   
       private static List<Address> getAddresss() {
            List<Address> addresses = new ArrayList<Address>();
   
            Address address1 = new Address();
            address1.setZip(12345678);
            address1.setStreet("St 155");
            address1.setNumber(123);
   
            addresses.add(address1);
   
            Address address2 = new Address();
            address2.setZip(87654321);
            address2.setStreet("St Saint Louis");
            address2.setNumber(321);
            addresses.add(address2);
   
            return addresses;
       }
  }

When you run the code in this list it's possible to see in the database the presence of two new persisted information. The rest of the process is now simpler, just add this method in Listing 10 and run it from the main method, it will be responsible for making the deletion of data and dependencies using orphanRemoval previously configured.

Listing 10. A method of removing people

private void removePerson() {
       ApplicationContext ctx =
                  new ClassPathXmlApplicationContext("spring-context.xml");
       JusticeLeagureService service =
                  (JusticeLeagureService) ctx.getBean("personService");
   
       Person person = service.getPersonById(1l);
       List<Address> addresss = person.getListAddresss();
       
       for (int i = 0; i < addresss.size(); i++) {
            Address address = addresss.get(i);
            if (address.getStreet().equalsIgnoreCase("St Saint Louis")) {
                  addresss.remove(i);
                  break;
            }
   
       }
       service.handlePersonCreateUpdate(person);
  }

And that's it. If execution function properly you will see when the execution finish the first person registered successfully being removed. This is only a brief presentation of what Hibernate is able to do before your specification. If something does not work, comment on the article. Thanks and see you soon!

Links

Official Site - http://docs.oracle.com/cd/E19798-01/821-1841/giqxy/

Example of use - http://docs.oracle.com/javaee/6/api/javax/persistence/OneToMany.html



Web developer and passioned for web design, SEO and front end technologies.

What did you think of this post?
Services
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually – in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits – in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login