Careeroza
Choosing a Strategy
Comparison
| Strategy | Tables | Polymorphic query | NOT NULL on subclass fields | Best when |
|---|---|---|---|---|
SINGLE_TABLE | 1 | fastest (no joins) | no | few subclass fields, frequent polymorphic queries (default choice) |
JOINED | 1 + one per subclass | joins | yes | many subclass fields, strict constraints |
TABLE_PER_CLASS | one per concrete class | UNION ALL | yes | rare polymorphic queries |
@MappedSuperclass | one per entity | not possible | yes | shared technical fields only |
Decision Flow
Do you need to query or reference the PARENT type (Payment)?
├── no ──► @MappedSuperclass
└── yes ──► Do subclasses add only a few columns?
├── yes ──► SINGLE_TABLE (+ CHECK constraints / validation)
└── no ──► Need NOT NULL & normalized data, can afford joins?
├── yes ──► JOINED
└── no ──► TABLE_PER_CLASSTip: Do not reach for inheritance by default. A single Payment entity with a method enum and a JSON details column is often simpler than any hierarchy. Prefer composition (embeddables) when the "is-a" relationship is weak.
Practice
Exercise: ShopEase adds notifications: EmailNotification(to, subject), SmsNotification(phone), PushNotification(deviceToken), all with message and sentAt. The admin page lists all notifications newest first. Which strategy, and how do you map it?
Show answer
// Few extra columns + a polymorphic list page -> SINGLE_TABLE
@Entity
@Table(name = "notifications")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "channel")
public abstract class Notification extends BaseEntity {
private String message;
private Instant sentAt;
}
@Entity @DiscriminatorValue("EMAIL") public class EmailNotification extends Notification { private String toAddress; private String subject; }
@Entity @DiscriminatorValue("SMS") public class SmsNotification extends Notification { private String phone; }
@Entity @DiscriminatorValue("PUSH") public class PushNotification extends Notification { private String deviceToken; }
// one query, no joins:
Page<Notification> findAllByOrderBySentAtDesc(Pageable pageable);