Labels

Friday, 21 February 2014

[HIBERNATE] property: hibernate.hbm2ddl.auto

hibernate.hbm2ddl.auto Automatically validates or exports schema DDL to the database when the SessionFactory is created. With create-drop, the database schema will be dropped when the SessionFactory is closed explicitly.
e.g. validate | update | create | create-drop
So the list of possible options are,
  • validate: validate the schema, makes no changes to the database.
  • update: update the schema.
  • create: creates the schema, destroying previous data.
  • create-drop: drop the schema at the end of the session.
These options seem intended to be developers tools and not to facilitate any production level databases, you may want to have a look at the following question; Hibernate: hbm2ddl.auto=update in production?

Wednesday, 19 February 2014

[HIBERNATE] one-to-one mapping using annotations

Hibernate one-to-one mapping using annotations

If you are working on any hibernate project or you are planning to work on any in future, then you can easily understand the one-to-one relationships between several entities in your application. In this post, i will discuss variations of one-to-one mappings supported in hibernate.
Download source code
Sections in this post:
Various supported techniques
Using foreign key association
Using a common join table
Using shared primary key
For this article, I am extending the example written for hello world example. We have two entities here: Employee and Account.

Various supported techniques

In hibernate there are 3 ways to create one-to-one relationships between two entities. Either way you have to use @OneToOne annotation. First technique is most widely used and uses a foreign key column in one to table. Second technique uses a rather known solution of having a third table to store mapping between first two tables. Third technique is something new which uses a common primary key value in both the tables.
Lets see them in action one by one:

Using foreign key association

In this association, a foreign key column is created in owner entity. For example, if we make EmployeeEntity owner, then a extra column “ACCOUNT_ID” will be created in Employee table. This column will store the foreign key for Account table.
Table structure will be like this:
foreign key association one to one
To make such association, refer the account entity in EmployeeEntity class as follow:
1.@OneToOne
2.@JoinColumn(name="ACCOUNT_ID")
3.private AccountEntity account;
The join column is declared with the @JoinColumn annotation which looks like the @Column annotation. It has one more parameters named referencedColumnName. This parameter declares the column in the targeted entity that will be used to the join.
If no @JoinColumn is declared on the owner side, the defaults apply. A join column(s) will be created in the owner table and its name will be the concatenation of the name of the relationship in the owner side, _ (underscore), and the name of the primary key column(s) in the owned side.
In a bidirectional relationship, one of the sides (and only one) has to be the owner: the owner is responsible for the association column(s) update. To declare a side as not responsible for the relationship, the attribute mappedBy is used. mappedBy refers to the property name of the association on the owner side.
1.@OneToOne(mappedBy="account")
2.private EmployeeEntity employee;
Above “mappedBy” attribute declares that it is dependent on owner entity for mapping.
Lets test above mappings in running code:
 01.public class TestForeignKeyAssociation {  
 03.  public static void main(String[] args) {  
 04.    Session session = HibernateUtil.getSessionFactory().openSession();  
 05.    session.beginTransaction();  
 06.   
 07.    AccountEntity account = new AccountEntity();  
 08.    account.setAccountNumber("123-345-65454");  
 09.   
 10.    // Add new Employee object  
 11.    EmployeeEntity emp = new EmployeeEntity();  
 12.    emp.setEmail("demo-user@mail.com");  
 13.    emp.setFirstName("demo");  
 14.    emp.setLastName("user");  
 15.   
 16.    // Save Account  
 17.    session.saveOrUpdate(account);  
 18.    // Save Employee  
 19.    emp.setAccount(account);  
 20.    session.saveOrUpdate(emp);  
 21.   
 22.    session.getTransaction().commit();  
 23.    HibernateUtil.shutdown();  
 24.  }  
 25.}  
Running above code creates desired schema in database and run these SQL queries.
1.Hibernate: insert into ACCOUNT (ACC_NUMBER) values (?)
2.Hibernate: insert into Employee (ACCOUNT_ID, EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?, ?)
You can verify the data and mappings in both tables when you run above program.. :-)

Using a common join table

This approach is not new to all of us. Lets start with targeted DB structure in this technique.
join table one to one mapping
In this technique, main annotation to be used is @JoinTable. This annotation is used to define the new table name (mandatory) and foreign keys from both of the tables. Lets see how it is used:
1.@OneToOne(cascade = CascadeType.ALL)
2.@JoinTable(name="EMPLOYEE_ACCCOUNT", joinColumns = @JoinColumn(name="EMPLOYEE_ID"),
3.inverseJoinColumns = @JoinColumn(name="ACCOUNT_ID"))
4.private AccountEntity account;
@JoinTable annotation is used in EmployeeEntity class. It declares that a new table EMPLOYEE_ACCOUNT will be created with two columns EMPLOYEE_ID (primary key of EMPLOYEE table) and ACCOUNT_ID (primary key of ACCOUNT table).
Testing above entities generates following SQL queries in log files:
1.Hibernate: insert into ACCOUNT (ACC_NUMBER) values (?)
2.Hibernate: insert into Employee (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
3.Hibernate: insert into EMPLOYEE_ACCCOUNT (ACCOUNT_ID, EMPLOYEE_ID) values (?, ?)

Using shared primary key

In this technique, hibernate will ensure that it will use a common primary key value in both the tables. This way primary key of EmployeeEntity can safely be assumed the primary key of AccountEntity also.
Table structure will be like this:
shared primary key one to one
In this approach, @PrimaryKeyJoinColumn is the main annotation to be used.Let see how to use it.
1.@OneToOne(cascade = CascadeType.ALL)
2.@PrimaryKeyJoinColumn
3.private AccountEntity account;
In AccountEntity side, it will remain dependent on owner entity for the mapping.
1.@OneToOne(mappedBy="account", cascade=CascadeType.ALL)
2.private EmployeeEntity employee;
Testing above entities generates following SQL queries in log files:
1.Hibernate: insert into ACCOUNT (ACC_NUMBER) values (?)
2.Hibernate: insert into Employee (ACCOUNT_ID, EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?, ?)
So, we have seen all 3 types of one to one mappings supported in hibernate. I will suggest you to download the source code and play with it.
Happy Learning !!

Download source code



Source: http://howtodoinjava.com/2012/11/15/hibernate-one-to-one-mapping-using-annotations/

Tuesday, 18 February 2014

[HIBERNATE] Compound Primary Key in Hibernate

In this code how to generate a Java class for composite key (how to composite key in hibernate):
create table Time (
        levelStation int(15) not null,
        src varchar(100) not null,
        dst varchar(100) not null,
        distance int(15) not null,
        price int(15) not null,
        confPathID int(15) not null,
        constraint ConfPath_fk foreign key(confPathID) references ConfPath(confPathID),
        primary key (levelStation,ConfPathID)
)ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;
To map a composite key, you can use the EmbeddedId or the IdClass annotations. I know this question is not strictly about JPA but the rules defined by the specification also applies. So here they are:

2.1.4 Primary Keys and Entity Identity

...
A composite primary key must correspond to either a single persistent field or property or to a set of such fields or properties as described below. A primary key class must be defined to represent a composite primary key. Composite primary keys typically arise when mapping from legacy databases when the database key is comprised of several columns. The EmbeddedId and IdClass annotations are used to denote composite primary keys. See sections 9.1.14 and 9.1.15.
...
The following rules apply for composite primary keys:
  • The primary key class must be public and must have a public no-arg constructor.
  • If property-based access is used, the properties of the primary key class must be public or protected.
  • The primary key class must be serializable.
  • The primary key class must define equals and hashCode methods. The semantics of value equality for these methods must be consistent with the database equality for the database types to which the key is mapped.
  • A composite primary key must either be represented and mapped as an embeddable class (see Section 9.1.14, “EmbeddedId Annotation”) or must be represented and mapped to multiple fields or properties of the entity class (see Section 9.1.15, “IdClass Annotation”).
  • If the composite primary key class is mapped to multiple fields or properties of the entity class, the names of primary key fields or properties in the primary key class and those of the entity class must correspond and their types must be the same.

With an IdClass

The class for the composite primary key could look like (could be a static inner class):
public class TimePK implements Serializable {
    protected Integer levelStation;
    protected Integer confPathID;

    public TimePK() {}

    public TimePK(Integer levelStation, String confPathID) {
        this.id = levelStation;
        this.name = confPathID;
    }
    // equals, hashCode
}
And the entity:
@Entity
@IdClass(TimePK.class)
class Time implements Serializable {
    @Id
    private Integer levelStation;
    @Id
    private Integer confPathID;

    private String src;
    private String dst;
    private Integer distance;
    private Integer price;

    // getters, setters
}
The IdClass annotation maps multiple fields to the table PK.

With EmbeddedId

The class for the composite primary key could look like (could be a static inner class):
@Embeddable
public class TimePK implements Serializable {
    protected Integer levelStation;
    protected Integer confPathID;

    public TimePK() {}

    public TimePK(Integer levelStation, String confPathID) {
        this.id = levelStation;
        this.name = confPathID;
    }
    // equals, hashCode
}
And the entity:
@Entity
class Time implements Serializable {
    @EmbeddedId
    private TimePK timePK;

    private String src;
    private String dst;
    private Integer distance;
    private Integer price;

    //...
}
The @EmbeddedId annotation maps a PK class to table PK.

Differences:

  • From the physical model point of view, there are no differences
  • EmbeddedId somehow communicates more clearly that the key is a composite key and IMO makes sense when the combined pk is either a meaningful entity itself or it reused in your code.
  • @IdClass is useful to specify that some combination of fields is unique but these do not have a special meaning.
They also affect the way you write queries (making them more or less verbose):
  • with IdClass
    select t.levelStation from Time t
  • with EmbeddedId
    select t.timePK.levelStation from Time t

References

  • JPA 1.0 specification
    • Section 2.1.4 "Primary Keys and Entity Identity"
    • Section 9.1.14 "EmbeddedId Annotation"
    • Section 9.1.15 "IdClass Annotation"

Hibernate is really great but it definitely needs some skills and experience: knowledge of ORM concepts, mappings and relations are welcome, understanding of how the Session works, understanding of more advanced concepts like lazy-loading, fetching strategies, caching (first-level cache, second-level cache, query cache), etc.
Sure, when used correctly, Hibernate is an awesome weapon: it's efficient, it will generate better SQL queries than lots (most?) of developers, it's very powerful, it has great performances, etc. However, I've seen many project using it very badly (e.g. not using associations because they were scared to "fetch the whole database" and this is far from the worst horror) and I'm thus always a bit suspicious when I hear "we are doing Hibernate". Actually, in the wrong hands, it can be a real disaster.
So, if I had to mention one weakness, it would be the learning curve. Don't underestimate it.

Source: http://stackoverflow.com/questions/1607819/weaknesses-of-hibernate/1609631#1609631

Thursday, 6 February 2014