Understanding @Id in Depth
In Java Persistence API (JPA), the @Id annotation is used to mark a field as the primary key of an entity. This primary key uniquely identifies each record in the corresponding database table. Below is a detailed breakdown of the purpose and functionality of @Id.
1. Primary Key in JPA
The primary key is a fundamental concept in relational databases and is crucial for ensuring the integrity and uniqueness of records. In JPA, marking a field with @Id makes it the unique identifier of the entity.
Basic Usage of @Id
When a field is annotated with @Id, JPA recognizes it as the primary key of the entity and uses it for:
- Identifying entities uniquely
- Performing lookups (i.e., finding a specific entity in the database)
- Managing entity persistence and relationships
- Ensuring that no two entities share the same primary key
Example of a Simple Primary Key:
@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
- Here,
idis the primary key of theCustomerentity. - The
@GeneratedValueannotation tells JPA to auto-generate values (e.g., using a database sequence or auto-increment).
2. @Id in Composite Keys
A composite key is when two or more columns together form a unique identifier for an entity. In your provided code, the Payment entity uses a composite key, meaning that a combination of customerNumber and checkNumber uniquely identifies each payment.
Why Use a Composite Key?
- Some business rules require composite keys (e.g., an order might be uniquely identified by
orderIdandcustomerIdtogether). - Helps maintain data integrity when no single column can uniquely identify a record.
How @Id Works in Composite Keys
- Since a composite key consists of multiple fields, each of them must be marked with
@Id. - The
@IdClass(PaymentId.class)annotation specifies an external primary key class (PaymentId) that contains the logic for defining equality and hashing.
Example: Composite Key Implementation
@Entity
@Table(name = "payments")
@IdClass(PaymentId.class) // Composite Key
public class Payment {
@Id
@ManyToOne
@JoinColumn(name = "customerNumber", referencedColumnName = "customerNumber")
private Customer customer; // FK to Customers
@Id
@Column(name = "checkNumber", length = 50)
private String checkNumber;
@Column(name = "paymentDate", nullable = false)
private LocalDate paymentDate;
@Column(name = "amount", precision = 10, scale = 2, nullable = false)
private BigDecimal amount;
}
-
customerNumberandcheckNumbertogether act as the primary key. - The
@IdClass(PaymentId.class)annotation tells JPA that this entity uses a composite key defined in a separate class (PaymentId).
The Composite Key Class (PaymentId)
import java.io.Serializable;
import java.util.Objects;
public class PaymentId implements Serializable {
private Long customer; // Must match entity field types
private String checkNumber;
public PaymentId() {}
public PaymentId(Long customer, String checkNumber) {
this.customer = customer;
this.checkNumber = checkNumber;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PaymentId paymentId = (PaymentId) o;
return Objects.equals(customer, paymentId.customer) &&
Objects.equals(checkNumber, paymentId.checkNumber);
}
@Override
public int hashCode() {
return Objects.hash(customer, checkNumber);
}
}
- This class must implement
Serializable. -
equals()andhashCode()ensure that JPA can properly compare composite keys.
3. How @Id Affects Persistence
JPA and Hibernate use the @Id field(s) in several ways:
- Uniqueness Enforcement: Ensures that each record in the table has a unique primary key.
-
Retrieving Entities: Used to fetch entities with
EntityManager.find()orSpring Data JPA findById(). - Updating & Deleting: JPA uses the primary key for identifying rows to update or delete.
-
Relationships & Foreign Keys: In many-to-one relationships, the
@Idfield(s) can serve as foreign keys.
4. Best Practices When Using @Id
- Prefer a Single Primary Key When Possible: Composite keys add complexity and can make querying more difficult.
-
Ensure
@IdClassMatches Entity Fields: The@IdClassfields must match those in the entity (same name and type). -
Implement
equals()andhashCode()Correctly: Composite key classes must override these methods properly. -
Use
@GeneratedValuefor Auto-Generation (when applicable): Helps avoid manually setting IDs for new records. -
Consider Using
@EmbeddedIdInstead of@IdClass:@EmbeddedIdis another way to define composite keys.
Example:
@Embeddable
public class PaymentId implements Serializable {
private Long customer;
private String checkNumber;
}
And in the entity:
@EmbeddedId
private PaymentId id;
This avoids having to use @IdClass.
Summary
-
@Idmarks a field as the primary key of an entity. - It ensures uniqueness and is used for querying, updating, and deleting records.
- When using composite keys, multiple fields are marked with
@Id, and an external key class (@IdClass) is required. -
@IdClassmust implementSerializableand properly defineequals()andhashCode(). -
@EmbeddedIdis an alternative approach for composite keys.
Top comments (0)