There are people who advocate the fact that mapping with @EmbeddedId are more expressive and clear, because you can directly access the class that has the composite 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 given field is part of a composite key and is not a simple entity field makes all the difference. That, just the @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, at face, transmits much more information on mapping.
Another example of difference between queries one and the other 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 the @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 is a matter of business need and code clarity that will define which mapping you will use. In practice, they both do, and quite rightly, the same thing.