Excellent follow-up! Here's a comprehensive guide to explain Hibernate Mapping using your Hotel Management System project. This is a critical topic for 3+ years experienced developers.
The Opening Pitch
"Hibernate mapping is how we tell Hibernate to connect our Java objects (entities) to database tables. In my Hotel Management System, I used various mapping strategies to model real-world relationships between guests, rooms, bookings, and payments."
The 4 Types of Mappings (With Hotel Examples)
1. Entity Mapping (@entity, @Table, @id)
Basic mapping of a Java class to a database table.
In my Hotel System:
@Entity @Table(name = "guests") public class Guest { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "guest_id") private Long id; @Column(name = "full_name", nullable = false, length = 100) private String name; @Column(unique = true) // Email must be unique private String email; @Transient // This won't be stored in database private int age; // Calculated from DOB, not stored }Why this matters: "This maps our
Guestobject to thegueststable. Hibernate handles all CRUD operations—I just work with objects."
2. One-to-One Mapping (@OneToOne)
One entity has exactly one related entity.
In my Hotel System:
@Entity @Table(name = "guests") public class Guest { @Id private Long id; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "passport_id") // Foreign key in guests table private Passport passport; // Each guest has exactly one passport } @Entity public class Passport { @Id private Long id; private String passportNumber; @OneToOne(mappedBy = "passport") // Bi-directional mapping private Guest guest; // This passport belongs to one guest }Real scenario: "We used this for guest and passport details. When we save a guest with cascade, Hibernate automatically saves the passport first, then links it."
3. One-to-Many / Many-to-One (The Most Common)
One entity has many related entities. This is everywhere in hotel systems!
In my Hotel System:
Scenario 1: Room → Bookings (One room has many bookings over time)
@Entity public class Room { @Id private Long roomNumber; @OneToMany(mappedBy = "room", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private List<Booking> bookings = new ArrayList<>(); // Helper method to maintain both sides public void addBooking(Booking booking) { bookings.add(booking); booking.setRoom(this); } } @Entity public class Booking { @Id private Long bookingId; @ManyToOne @JoinColumn(name = "room_number") // Foreign key in bookings table private Room room; }Scenario 2: Guest → Bookings (One guest can have many bookings)
@Entity public class Guest { @OneToMany(mappedBy = "guest") private List<Booking> bookingHistory; }Important decision I made:
- Used LAZY fetching for
bookingslist—don't load all bookings when I just need room details- Used EAGER only when absolutely necessary (like loading a guest with their current active booking)
4. Many-to-Many (@ManyToMany)
Entities that have many-to-many relationships, usually with a join table.
In my Hotel System:
Scenario: Amenities/Facilities shared across rooms
@Entity public class Room { @Id private Long roomNumber; @ManyToMany @JoinTable( name = "room_amenities", // Join table name joinColumns = @JoinColumn(name = "room_id"), inverseJoinColumns = @JoinColumn(name = "amenity_id") ) private List<Amenity> amenities = new ArrayList<>(); // A room has many amenities (TV, AC, WiFi) // An amenity is in many rooms } @Entity public class Amenity { @Id private Long id; private String name; // "WiFi", "TV", "MiniBar" @ManyToMany(mappedBy = "amenities") private List<Room> rooms; }Better alternative I used: "Sometimes I prefer breaking Many-to-Many into two One-to-Manys with an intermediate entity for extra columns."
@Entity public class RoomAmenity { @Id private Long id; @ManyToOne @JoinColumn(name = "room_id") private Room room; @ManyToOne @JoinColumn(name = "amenity_id") private Amenity amenity; private LocalDate installedDate; // Extra column! private boolean isWorking; // Extra column! }
Advanced Mapping Concepts (For 3+ Years Experience)
Inheritance Mapping Strategies
In my Hotel System:
"We had different types of users with common and specific attributes."
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "user_type")
public abstract class User {
@Id
private Long id;
private String name;
private String email;
}
@Entity
@DiscriminatorValue("RECEPTIONIST")
public class Receptionist extends User {
private String deskLocation;
}
@Entity
@DiscriminatorValue("MANAGER")
public class Manager extends User {
private String department;
}
Why I chose SINGLE_TABLE: "Better performance—one table for all users, no joins needed. But if I had many subtype-specific fields, I'd use JOINED strategy."
Fetch Types Explained with Examples
In my Hotel System:
@Entity public class Booking { @ManyToOne(fetch = FetchType.EAGER) // Load guest immediately @JoinColumn(name = "guest_id") private Guest guest; // When showing booking, I always need guest name @OneToMany(mappedBy = "booking", fetch = FetchType.LAZY) private List<Payment> payments; // Load only when needed }
My rule of thumb:
- EAGER: When I'm 100% sure I'll need the related data (guest with booking)
- LAZY: When data might not be needed (payment history, room amenities)
Warning I handled: "LAZY loading outside transaction was causing LazyInitializationException. I fixed it by either:
- Keeping transaction open until view renders
- Using JOIN FETCH in queries when I know I need the data
- DTO projections for specific use cases"
Cascade Types (Real Usage)
In my Hotel System:
@Entity public class Booking { @OneToMany(mappedBy = "booking", cascade = CascadeType.ALL) private List<Payment> payments; // When I delete a booking, delete all its payments @ManyToOne(cascade = CascadeType.PERSIST) @JoinColumn(name = "guest_id") private Guest guest; // When I create a new booking with a new guest, save the guest too }
What I learned: "Never use CascadeType.ALL blindly. In hotel system, deleting a booking should NOT delete the guest—just the association."
The Complete Pitch Summary
"In my Hotel Management System, Hibernate mapping was crucial for:
**Basic mappings:*
@Entity,@Table,@Columnfor guests, rooms, bookings*Relationships:
@OneToManybetween Room and Bookings@ManyToOnebetween Booking and Guest@ManyToManybetween Room and Amenities (or break it with intermediate entity)@OneToOnebetween Guest and PassportPerformance optimizations:
- Used LAZY fetching for collections to avoid N+1 queries
- Used JOIN FETCH in JPQL when I need related data
- Applied appropriate cascade types based on business logic
**Inheritance:* Used SINGLE_TABLE strategy for different user types*
These mappings helped me model the real hotel domain accurately while maintaining good database performance."
Bonus: Common Interview Follow-ups
Q: "What's the difference between mappedBy and @JoinColumn?"
A: "mappedBy is used in the inverse side (the one without the foreign key) to point to the owner. @JoinColumn is used in the owning side to specify the foreign key column name."
Q: "When would you use @ElementCollection instead of @OneToMany?"
A: "For simple value types like a guest's list of phone numbers—where PhoneNumber isn't an entity with its own identity, just a collection of strings/embeddables."
Q: "How do you handle soft deletes?"
A: "I use @SQLDelete and @Where annotations to filter out deleted records, or a simple @Column boolean active flag and include that condition in all queries."
Top comments (0)