JPA - Composite Primary Keys
Composite Primary Keys
A composite key is a primary key that is made up of more than one column to uniquely identify records in a table. Unlike a single-column primary key, a composite key combines two or more columns to ensure uniqueness. While any of the individual columns in a composite key might not be unique on their own, together they form a unique combination that can uniquely identify each row in the table
source: https://www.geeksforgeeks.org/composite-key-in-sql/
A composite primary key, also called a composite key, is a combination of two or more columns to form a primary key for a table.
In JPA, we have two options to define the composite keys:
@IdClass
annotation@EmbeddedId
annotation
If we have a table called Account
and it has two columns, accountNumber
and accountType
, that form the composite key.
The IdClass Annotation
public class AccountId implements Serializable {
private String accountNumber;
private String accountType;
// default constructor
public AccountId(String accountNumber, String accountType) {
this.accountNumber = accountNumber;
this.accountType = accountType;
}
// equals() and hashCode()
}
Using AccountId
in the entity. In order to do that, we need to annotate the entity with the @IdClass
annotation. We must also declare the fields from the AccountId
class in the entity Account
and annotate them with @Id
@Entity
@IdClass(AccountId.class)
public class Account {
@Id
private String accountNumber;
@Id
private String accountType;
// other fields, getters and setters
}
The EmbeddedId Annotation
@Embeddable
public class BookId implements Serializable {
private String title;
private String language;
// default constructor
public BookId(String title, String language) {
this.title = title;
this.language = language;
}
// getters, equals() and hashCode() methods
}
Then we need to embed this class in the Book entity using @EmbeddedId
@Entity
public class Book {
@EmbeddedId
private BookId bookId;
// constructors, other fields, getters and setters
}
JPA Repository and Method Naming
@Repository
public interface BookRepository extends JpaRepository<Book, BookId> {
List<Book> findByIdName(String name);
List<Book> findByIdAuthor(String author);
}
We use a part of the id variable’s field names to derive our Spring Data query methods. Hence, JPA interprets the partial primary key query as:
findByIdName -> directive "findBy" field "id.name"
findByIdAuthor -> directive "findBy" field "id.author"
Major differeces
- With
@IdClass
, we have to specify the column names twice. Once in the Composite class definition. The second time in the entity definition. With@EmbeddedId
, we only specify the column names once. - For example, these different structures affect the JPQL queries that we write.
- With @IdClass, the query is a bit simpler:
SELECT account.accountNumber FROM Account account
- With @EmbeddedId, we have to do one extra traversal:
SELECT book.bookId.title FROM Book book
- With @IdClass, the query is a bit simpler: