Advanced Entity Mapping in JPA 🏗️
The Building Blocks Story
Imagine you’re building with LEGO blocks. Some blocks are special—they can be parents that share their shape with child blocks. Some blocks are containers that hold smaller pieces inside. And some blocks have magic powers that transform things!
That’s exactly how Advanced Entity Mapping works in JPA. Let’s explore each building block!
1. Entity Inheritance 👨👩👧👦
What is it?
Think of a family tree. Grandpa has certain traits (like brown eyes). Dad inherits those traits. You inherit from Dad!
In JPA, a parent entity can pass its fields to child entities. Just like how all vehicles have wheels, but cars and motorcycles are different!
@Entity
@Inheritance
public class Vehicle {
@Id
private Long id;
private int wheels;
}
@Entity
public class Car extends Vehicle {
private int doors;
}
@Entity
public class Motorcycle extends Vehicle {
private boolean hasSidecar;
}
Why use it?
- Share common fields (no copy-paste!)
- Query all vehicles at once
- Keep your code clean and organized
2. Single Table Inheritance 📋
One Big Family Table
Imagine ONE giant notebook where you write about ALL your pets—dogs, cats, birds. You add a label column saying “type: dog” or “type: cat”.
@Entity
@Inheritance(strategy =
InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "pet_type")
public class Pet {
@Id
private Long id;
private String name;
}
@Entity
@DiscriminatorValue("DOG")
public class Dog extends Pet {
private String breed;
}
@Entity
@DiscriminatorValue("CAT")
public class Cat extends Pet {
private boolean indoor;
}
The Database View
| id | pet_type | name | breed | indoor |
|---|---|---|---|---|
| 1 | DOG | Buddy | Labrador | null |
| 2 | CAT | Whiskers | null | true |
Pros: ⚡ Super fast queries! Cons: Many null columns
3. Joined Table Inheritance 🔗
Separate Rooms, Connected Doors
Now imagine each pet type has its OWN notebook, but they all link back to a master pet list.
@Entity
@Inheritance(strategy =
InheritanceType.JOINED)
public class Employee {
@Id
private Long id;
private String name;
}
@Entity
public class Manager extends Employee {
private String department;
}
@Entity
public class Developer extends Employee {
private String language;
}
The Database View
Employee Table:
| id | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
Manager Table:
| id | department |
|---|---|
| 1 | Sales |
Developer Table:
| id | language |
|---|---|
| 2 | Java |
Pros: ✅ No null columns, clean design Cons: 🐌 Slower (needs JOINs)
4. Mapped Superclass 📦
The Invisible Helper
Think of a recipe template. It’s not a dish itself, but every dish you make uses its structure!
A @MappedSuperclass gives fields to children but never becomes its own table.
@MappedSuperclass
public abstract class Auditable {
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private String createdBy;
}
@Entity
public class Product extends Auditable {
@Id
private Long id;
private String name;
private double price;
}
@Entity
public class Order extends Auditable {
@Id
private Long id;
private String orderNumber;
}
Result: Both Product and Order tables have createdAt, updatedAt, createdBy columns!
Key Difference from Inheritance:
- ❌ Cannot query
Auditabledirectly - ❌ No
Auditabletable exists - ✅ Just shares fields with children
5. Embeddable Classes 🎁
The Nested Gift Box
Imagine a gift box (your entity) containing a smaller box (embeddable) with jewelry inside. The small box isn’t separate—it’s PART of the gift!
@Embeddable
public class Address {
private String street;
private String city;
private String zipCode;
private String country;
}
@Entity
public class Customer {
@Id
private Long id;
private String name;
@Embedded
private Address homeAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(
name = "street",
column = @Column(
name = "work_street")),
@AttributeOverride(
name = "city",
column = @Column(
name = "work_city"))
})
private Address workAddress;
}
The Database View
| id | name | street | city | work_street | work_city |
|---|---|---|---|---|---|
| 1 | John | Oak St | NYC | Main Ave | Boston |
Why use it?
- 🎯 Group related fields together
- 🔄 Reuse the same structure
- 📦 Keep entities clean
6. JPA Attribute Converters 🔮
The Magic Translator
Imagine you speak English, but your database speaks Spanish. A Converter is your translator!
It transforms Java types ↔ Database types automatically.
@Converter(autoApply = true)
public class BooleanToYesNoConverter
implements AttributeConverter
<Boolean, String> {
@Override
public String convertToDatabaseColumn(
Boolean value) {
return value ? "Y" : "N";
}
@Override
public Boolean convertToEntityAttribute(
String dbValue) {
return "Y".equals(dbValue);
}
}
@Entity
public class Settings {
@Id
private Long id;
// Stored as "Y" or "N" in database!
private Boolean darkMode;
@Convert(converter =
JsonToMapConverter.class)
private Map<String, Object> config;
}
Common Use Cases
| Java Type | DB Type | Why? |
|---|---|---|
| Boolean | “Y”/“N” | Legacy databases |
| Enum | String | Readable values |
| List | JSON | Flexible storage |
| LocalDate | VARCHAR | Custom format |
7. JPA Collection Mapping 📚
The Bookshelf Organizer
You have a bookshelf (entity) with many books (collection). JPA helps you organize them in different ways!
ElementCollection - Simple Items
@Entity
public class User {
@Id
private Long id;
private String username;
@ElementCollection
@CollectionTable(
name = "user_phones",
joinColumns = @JoinColumn(
name = "user_id"))
@Column(name = "phone_number")
private Set<String> phoneNumbers;
@ElementCollection
@CollectionTable(name = "user_tags")
private List<String> tags;
}
Map Collections
@Entity
public class Student {
@Id
private Long id;
// Course name -> Grade
@ElementCollection
@MapKeyColumn(name = "course")
@Column(name = "grade")
private Map<String, String> grades;
}
Database Result
user_phones table:
| user_id | phone_number |
|---|---|
| 1 | 555-1234 |
| 1 | 555-5678 |
student_grades table:
| student_id | course | grade |
|---|---|---|
| 1 | Math | A |
| 1 | Science | B+ |
The Complete Picture 🎨
graph LR A["Entity Mapping"] --> B["Inheritance"] A --> C["Embeddables"] A --> D["Converters"] A --> E["Collections"] B --> B1["Single Table"] B --> B2["Joined Table"] B --> B3["Mapped Superclass"] C --> C1["Reusable Components"] D --> D1["Type Translation"] E --> E1["Lists & Maps"]
Quick Reference Card 🃏
| Feature | Use When… |
|---|---|
| Single Table | Few subclasses, need speed |
| Joined Table | Many fields, need normalization |
| Mapped Superclass | Share fields, no parent queries |
| Embeddable | Group fields, reuse structure |
| Converter | Transform types automatically |
| Collection | Store lists/sets/maps |
You Did It! 🎉
You just learned how to:
✅ Create entity hierarchies with inheritance ✅ Choose between Single Table and Joined strategies ✅ Share fields using Mapped Superclass ✅ Embed reusable components ✅ Convert types magically ✅ Map collections to database tables
These are the advanced building blocks that make JPA so powerful. Now go build something amazing!
💡 Pro Tip: Start simple with
@MappedSuperclassfor sharing audit fields, then explore inheritance when you truly need polymorphic queries!
