What is the difference between EmbeddedId and IdClass in Hibernate?

4

I have read in the Hibernate 5.0 documentation that you can implement composite primary keys using two forms.

The first one is using the @IdClass annotation and imitating the IdClass attributes in the original class.

The other is using the @EmbeddedId annotation, where you can create an inner / nested class and include a reference to it in the original class.

Is there any major difference between the two forms?

    
asked by anonymous 14.06.2018 / 18:07

2 answers

6

There are two ways to render the composite key into the entity.

Let's say you have a parametro , entity Parametro , and your composite key is nome and empresa :

nome | empresa | valor
taxa | 56      | 3.44

@EmbeddedId creates an abstraction within the entity that does not exist in the database table. It merges the information that makes up the composite key under the same variable:

 @Entity
 class Parametro {
      @EmbeddedId
      private ParametroId parametroId;
 }

 @Embeddable
 class ParametroId {
      private String nome;
      private Integer empresa;
 }

And this is reflected in the queries. Example in JPQL:

SELECT p FROM Parametro p where p.parametroId = :parametroId

There is no parametroId in the database, which may be a bit strange when querying in JPQL. And if you are only querying nome or empresa , the resulting JPQL looks very different from the generated SQL. See:

SELECT p FROM Parametro p where p.parametroId.empresa = :empresa

While @IdClass does not involve creating a new class with the table keys. So the queries get closer to the table in the database:

SELECT p FROM Parametro p where p.nome = :nome AND p.empresa = :empresa;

However, this flexibility makes the concept of "composite key" hidden. With @EmbeddedId the use of the compound key ends up being more natural in the code, especially if you are using CrudRepository of Spring, where to use @IdClass you need to simulate a class @EmbeddedId .

    
14.06.2018 / 20:55
3

There are people who advocate the fact that mappings with @EmbeddedId are more expressive and clear because you can directly access the class that has the compound key, something that is not possible with @IdClass . For example:

Mapping with @EmbeddedId :

@Embeddable class EmployeeId { 
  String name;
  LocalDate dataOfBirth;
}

@Entity class Employee {
  @EmbeddedId EmployeeId employeeId;
  ...
}

Mapping with @IdClass :

class EmployeeId { 
   String name;
   LocalDate dateOfBirth;
}

@Entity class Employee {
@IdClass(EmployeeId.class);
   @Id String name;
   @Id LocalDate dateOfBirth;
   ...
}

In HQL queries, most of the time, knowing that a particular field is part of a compound key and is not a simple field of the entity makes all the difference. That, only @EmbeddedId provides. Examples of queries of both:

select e.name from Employee e //@IdClass

select e.employeeId.name from Employee e //@EmbeddedId

The second query , of course, conveys much more information about the mapping.

Another example of a difference between queries of one and another to achieve the same result, in this case using the IN :

//com @EmbeddedId
FROM Entity WHERE id IN :ids

//com @IdClass
FROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN

On the other hand, there are very specific use cases where @IdClass is a much easier solution to use. For example, when one of the composite keys is also a relationship:

@Entity
@IdClass(PhonePK.class)
public class Phone {

    @Id
    private String type;

    @ManyToOne
    @Id
    @JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID")
    private Employee owner;
    ...
}

public class PhonePK {
    private String type;
    private long owner;
    ...
}

In short, it's a matter of business need and code clarity that will define which mapping you're going to use. In practice, both do, and very well, the same thing.

    
14.06.2018 / 20:43