# Your First Entity — Hibernate / JPA

Source: https://www.skillbyai.com/en/hibernate-jpa/f-entity

> Map a class with @Entity, @Id, @GeneratedValue, @Table and @Column.

## Mapping a class to a table

An **entity** is a class whose instances are persisted. Requirements: annotate it with **`@Entity`**; give it a **primary key** field with **`@Id`**; provide a **no-argument constructor** (it may be `protected`); and do not make the class or persistent methods `final` if you rely on lazy-loading proxies. By default the table and column names derive from the class and field names (Spring Boot's naming strategy converts `firstName` to `first_name`); use **`@Table(name = ...)`** and **`@Column(name = ..., nullable = false, length = ..., unique = ...)`** to be explicit. **`@GeneratedValue`** asks the provider to generate IDs (strategies are covered later). Fields that should not be persisted are marked **`@Transient`**. JPA can access state through **fields** (when `@Id` is on a field) or **properties** (getters); field access is the common modern choice. Entities are not plain data bags: keep invariants in constructors and domain methods, and expose only the setters you need. Java **records** cannot be entities, because entities must be mutable and proxyable, but records work well as **DTOs** and **embeddables** in recent versions.

## A product entity

Explicit table and column mapping, a protected constructor for JPA and a domain method.

```java
import jakarta.persistence.*;
import java.math.BigDecimal;

@Entity
@Table(name = "products", uniqueConstraints = @UniqueConstraint(columnNames = "sku"))
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_seq")
    @SequenceGenerator(name = "product_seq", sequenceName = "products_seq", allocationSize = 50)
    private Long id;

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

    @Column(nullable = false, length = 200)
    private String title;

    @Column(nullable = false, precision = 12, scale = 2)
    private BigDecimal price;

    @Transient
    private boolean recentlyViewed;          // not stored

    protected Product() { }                   // for JPA

    public Product(String sku, String title, BigDecimal price) {
        this.sku = sku;
        this.title = title;
        changePrice(price);
    }

    public void changePrice(BigDecimal newPrice) {
        if (newPrice.signum() < 0) throw new IllegalArgumentException("price must be >= 0");
        this.price = newPrice;
    }

    public Long getId() { return id; }
    public String getSku() { return sku; }
    public BigDecimal getPrice() { return price; }
}
```

## Use BigDecimal for money

Mapping prices to `double` causes rounding errors such as 0.1 + 0.2 ≠ 0.3. Use `BigDecimal` with an explicit `precision` and `scale`, matching a `NUMERIC(12,2)` column.

**Quiz:** Which is required for a JPA entity class?

- [ ] A public all-arguments constructor only
- [ ] Every field marked @Column
- [x] An @Id field and a no-argument constructor (which may be protected)
- [ ] The class must be a record

*Answer:* An @Id field and a no-argument constructor (which may be protected). Entities need a primary key and a no-arg constructor that the provider can call.
