Home/Learn/Hibernate & JPA/@Entity, @Table, @Id

@Entity, @Table, @Id

Beginner
Fundamentals

@Entity marks a class as a JPA-managed entity; @Table customises the table name and schema; @Id designates the primary key field; every entity must have exactly one @Id.

Overview

@Entity registers a Java class as a JPA-managed persistent object. Hibernate maps it to a database table. By default the table name matches the class name (case-insensitive). @Table customises the table name, schema, catalog, and adds unique constraints. @Id marks the primary key field — every entity must have exactly one. Composite primary keys use @IdClass or @EmbeddedId. Entities must have a no-arg constructor (public or protected) for Hibernate to instantiate them during load.

@Entity & @Table

@Entity is required on every persistent class. @Table is optional — use it when the table name differs from the class name, or when you need to define unique constraints or indexes at the JPA level.

Java — @Entity, @Table with constraints and indexes
// Basic entity — table name defaults to "Product" (case-insensitive)
@Entity
public class Product {
    @Id
    private Long id;
    private String name;
}

// Custom table name, schema, and unique constraint
@Entity
@Table(
    name    = "tbl_products",
    schema  = "shop",
    uniqueConstraints = {
        @UniqueConstraint(name = "uq_product_sku", columnNames = {"sku"}),
        @UniqueConstraint(name = "uq_product_barcode", columnNames = {"barcode_type", "barcode_value"})
    },
    indexes = {
        @Index(name = "idx_product_category", columnList = "category_id"),
        @Index(name = "idx_product_name",     columnList = "name")
    }
)
public class Product {
    @Id
    private Long id;

    @Column(nullable = false, length = 50)
    private String sku;

    @Column(name = "barcode_type", length = 10)
    private String barcodeType;

    @Column(name = "barcode_value", length = 50)
    private String barcodeValue;

    // JPA requires a no-arg constructor (public or protected)
    protected Product() {}
    public Product(Long id, String sku) { this.id = id; this.sku = sku; }
}

@Id and Composite Keys

@Id marks the primary key. For composite PKs, use @IdClass (two fields, separate class) or @EmbeddedId (single @Embeddable PK class). @IdClass is simpler for JPQL; @EmbeddedId is more type-safe.

Java — single PK, @IdClass, @EmbeddedId
// Single PK — most common
@Entity
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
}

// Composite PK with @IdClass
public class OrderItemId implements Serializable {
    private Long orderId;
    private Long productId;
    // equals + hashCode required
}

@Entity
@IdClass(OrderItemId.class)
@Table(name = "order_items")
public class OrderItem {
    @Id
    @Column(name = "order_id")
    private Long orderId;

    @Id
    @Column(name = "product_id")
    private Long productId;

    private int quantity;
}

// Composite PK with @EmbeddedId (type-safe)
@Embeddable
public class OrderItemId implements Serializable {
    private Long orderId;
    private Long productId;
    // equals + hashCode
}

@Entity
@Table(name = "order_items")
public class OrderItem {
    @EmbeddedId
    private OrderItemId id;
    private int quantity;
}

Entity Requirements & Best Practices

JPA imposes several requirements on entity classes. Following best practices ensures Hibernate works efficiently and avoids common pitfalls.

Java — entity requirements and best practices
// JPA entity requirements:
// ✓ Must be annotated @Entity
// ✓ Must have a no-arg constructor (public or protected)
// ✓ Must have exactly one @Id field
// ✓ Must NOT be final (Hibernate needs to subclass for lazy proxies)
// ✓ Fields/methods must NOT be final either

// Best practices:
@Entity
@Table(name = "customers")
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // ✓ Use field access (annotations on fields) — consistent access type
    @Column(nullable = false, length = 254)
    private String email;

    // ✓ Implement equals/hashCode based on business key (NOT id)
    //   because id is null for transient entities
    @NaturalId
    private String email;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Customer c)) return false;
        return email != null && email.equals(c.email);
    }

    @Override
    public int hashCode() { return Objects.hashCode(email); }
}

Key Points to Remember

  • 1@Entity is required; @Table is optional — use it to customise table name or add constraints.
  • 2Every entity must have exactly one @Id field and a no-arg constructor.
  • 3Entities must not be final — Hibernate needs to subclass them for lazy proxying.
  • 4@IdClass and @EmbeddedId support composite primary keys.
  • 5Implement equals/hashCode based on a business key (natural ID), not the generated DB id.
  • 6Define unique constraints and indexes via @Table annotations for JPA-managed schema generation.

Interview Questions

Sign in to ask Aria
1

Why must a JPA entity have a no-arg constructor?

EasyTCS
2

Why should JPA entity classes not be declared final?

MediumPivotal
3

How do you map a composite primary key in JPA?

MediumAmazon
4

Why should you implement equals/hashCode on a business key rather than the generated ID?

HardNetflix
5

What is the difference between @IdClass and @EmbeddedId for composite keys?

HardInfosys

Ask Aria about @Entity, @Table, @Id

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…