Labels

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

No comments:

Post a Comment