JPA Entities
An entity is a Java class that maps to a database table. JPA (Java Persistence API) handles the mapping automatically.
Basic Entity
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 255)
private String name;
@Column(length = 2000)
private String description;
@Column(nullable = false, precision = 10, scale = 2)
private BigDecimal price;
@Column(nullable = false)
private Integer stockQuantity;
@Column(nullable = false)
private Boolean active = true;
@CreationTimestamp
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
// Constructors
public Product() {}
public Product(String name, String description, BigDecimal price, Integer stockQuantity) {
this.name = name;
this.description = description;
this.price = price;
this.stockQuantity = stockQuantity;
this.active = true;
}
// Getters and Setters
public Long getId() { return id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public BigDecimal getPrice() { return price; }
public void setPrice(BigDecimal price) { this.price = price; }
// ... other getters/setters
}
Key JPA Annotations
| Annotation | Purpose |
|---|---|
@Entity |
Marks class as a JPA entity |
@Table |
Specifies table name |
@Id |
Marks primary key field |
@GeneratedValue |
Auto-generates ID values |
@Column |
Column configuration (name, nullable, length) |
@CreationTimestamp |
Auto-sets on creation |
@UpdateTimestamp |
Auto-updates on modification |
Entity Relationships
One-to-Many (Category → Products):
@Entity
@Table(name = "categories")
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@OneToMany(mappedBy = "category", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Product> products = new ArrayList<>();
}
Many-to-One (Product → Category):
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id", nullable = false)
private Category category;
}
Many-to-Many (Product ↔ Tag):
@Entity
@Table(name = "products")
public class Product {
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "product_tags",
joinColumns = @JoinColumn(name = "product_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private Set<Tag> tags = new HashSet<>();
}
Fetch Types
| Type | Behavior |
|---|---|
FetchType.LAZY |
Load only when accessed (default for collections) |
FetchType.EAGER |
Load immediately with parent (default for @ManyToOne) |
Best Practice: Always use FetchType.LAZY and fetch eagerly only when needed with @EntityGraph or JPQL joins.
Entity Best Practices
Never Use Entities as API Responses
// BAD: Exposes internal data, causes lazy loading issues, circular references
@GetMapping("/{id}")
public Product getProduct(@PathVariable Long id) {
return productRepository.findById(id).orElseThrow();
// Returns JSON with password hashes, internal fields, lazy-loaded collections
}
// GOOD: Convert to DTO
@GetMapping("/{id}")
public ProductDto getProduct(@PathVariable Long id) {
return productService.getProduct(id);
// Returns only the data the client needs
}
Avoid LazyInitializationException
// BAD: Lazy collection accessed outside transaction
@Entity
public class Order {
@OneToMany(fetch = FetchType.LAZY)
private List<OrderItem> items;
}
// In service — throws LazyInitializationException:
Order order = orderRepository.findById(id).orElseThrow();
order.getItems().size(); // Error! Transaction is closed
// SOLUTION 1: Fetch join in query
@Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id")
Order findByIdWithItems(@Param("id") Long id);
// SOLUTION 2: Use @EntityGraph
@EntityGraph(attributePaths = {"items"})
@Query("SELECT o FROM Order o WHERE o.id = :id")
Order findByIdWithItems(@Param("id") Long id);
// SOLUTION 3: Use FetchType.EAGER (not recommended — causes N+1)
Entity Design Rules
- Private fields + getters/setters — encapsulation
- No-arg constructor required — JPA needs to instantiate entities
- Use @GeneratedValue — let the database generate IDs
- Use BigDecimal for money — never double/float
- Add @Column constraints — nullable, length, precision
- Use @CreationTimestamp/@UpdateTimestamp — for audit trail
Practice Problems
Design and implement a solution for Entity in a backend system. Consider scalability, error handling, and production readiness.
Solution
// Entity implementation
// Key aspects: validation, error handling, logging, testing
public class Entity {
// Production-ready implementation
}Identify and handle edge cases for Entity. What happens under high load, with invalid input, or during failures?
Solution
// Edge case handling:
// 1. Null/empty input -> validation
// 2. High load -> rate limiting, queuing
// 3. Failures -> retries, circuit breaker
// 4. Concurrent access -> locks, idempotencyWrite a testing strategy for Entity. Include unit tests, integration tests, and performance tests.
Solution
// Test plan:
// - Unit: 80% coverage target
// - Integration: API contracts
// - Performance: latency, throughput
// - Chaos: failure injectionQuiz
1. What is LazyInitializationException and how do you prevent it?
2. Why should you use BigDecimal instead of double for prices?
3. What is the primary purpose of Entity?
4. What is a common mistake when implementing Entity?
Flashcards
Question
What does @Entity do?
Click to reveal answer
Answer
Maps a Java class to a database table
Question
What is LazyInitializationException?
Click to reveal answer
Answer
Error when accessing a lazy-loaded collection after the transaction closes
Question
What is Entity?
Click to reveal answer
Answer
Entity is a key concept in backend development.
Question
When to use Entity?
Click to reveal answer
Answer
Use Entity when building production systems that require reliability, scalability, and maintainability.
Question
Entity best practices
Click to reveal answer
Answer
Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.
Revision Notes
Key Takeaways
- 1.Entity = Java class mapped to a database table via JPA
- 2.Use @Id, @GeneratedValue, @Column, @ManyToOne, @OneToMany etc.
- 3.Always use FetchType.LAZY for collections
- 4.Never expose entities directly as API responses — use DTOs
- 5.Use BigDecimal for money, never double/float
Interview Tips
- •Explain N+1 problem and how to solve it
- •Know the difference between FetchType.LAZY and EAGER
- •Understand entity relationships (@ManyToOne, @OneToMany, @ManyToMany)
Cheat Sheet
JPA Entities
- @Entity: Maps class to table
- @Id + @GeneratedValue: Auto-generated primary key
- Relationships: @ManyToOne, @OneToMany, @ManyToMany
- FetchType.LAZY: Load on access (preferred)
- Avoid: LazyInitializationException, N+1, double for money