Search This Blog

Tuesday, 5 November 2013

Components in JPA

We have used components in Hibernate. They provide a very good technique for code reuse. They are also useful if we do now want to represent a particular table as Entity and give them their own separate life cycle. JPA also provides support for components.
Consider the below component:
@Embeddable
public class Address {

 @Column(name = "CITY")
 private String city;
 @Column(name = "ZIP_CODE")
 private String zipCode;
 @Embedded
 private State state;
 @org.hibernate.annotations.Parent
 private User user;
        //setter getters 
}
The first line in the code is the Embeddable Annotation.It indicates that the class will be used as a component in other Entities. The next two fields are simple OR mappings.
A Component, as we saw with Hibernate is capable of being composed of other components. Here the Address class includes a State component. That is where the Embedded annotation comes into the picture. The annotation indicates that the object is a component placed within this class - entity or component.
The last annotation is a custom annotation. Hibernate allows components to hold back references to the owning entity. JPA does not provide the same functionality. To achieve the same we need to use the custom Parent annotation.
The User class is as below:
@Entity
@Table(name = "ADRESSED_USER")
public class User {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Long id;
 @Column(name = "NAME")
 private String name;
 @Embedded
 private Address address;
//.. setter getters
}
As seen the User has the component embedded within it. The State class is as below:
@Embeddable
public class State {

 @Column(name = "STATE_NAME")
 private String name;
//.. setter getters
}
If we look at the above code carefully we can see that our State component includes a name property. The same property is also present within the User class. However the mapped SQL name for both columns is different. This is necessary - as both columns are in the same table they cannot have the same name.
The table generated by Hibernate for the below is :
11344 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport  - 
    create table firstOne.ADRESSED_USER (
        id  bigserial not null,
        CITY varchar(255),
        STATE_NAME varchar(255),
        ZIP_CODE varchar(255),
        NAME varchar(255),
        primary key (id)
    )
I decided to test the code:
public static void testCreate() {
 EntityManager entityManager = emFactory.createEntityManager();
 EntityTransaction transaction = entityManager.getTransaction(); 
        transaction.begin();
 entityManager.persist(user);
 transaction.commit();
 long id = user.getId();
 entityManager.close();

 entityManager = emFactory.createEntityManager();
 user = entityManager.find(User.class, id);
 System.out.println("name is " + user.getAddress().getUser().getName() );
}
As seen the Parent property allowed us to get access to the User name (through a very convoluted process!).
4750 [main] DEBUG org.hibernate.SQL  - 
    select
        user0_.id as id0_0_,
        user0_.CITY as CITY0_0_,
        user0_.STATE_NAME as STATE3_0_0_,
        user0_.ZIP_CODE as ZIP4_0_0_,
        user0_.NAME as NAME0_0_ 
    from
        firstOne.ADRESSED_USER user0_ 
    where
        user0_.id=?

2 comments: