DEV Community

Er. Bhupendra
Er. Bhupendra

Posted on

What is mapping in Hibernate , How to expalin to Interviewer

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 Guest object to the guests table. 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 bookings list—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;
}
Enter fullscreen mode Exit fullscreen mode

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:

  1. Keeping transaction open until view renders
  2. Using JOIN FETCH in queries when I know I need the data
  3. 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, @Column for guests, rooms, bookings*

Relationships:

  • @OneToMany between Room and Bookings
  • @ManyToOne between Booking and Guest
  • @ManyToMany between Room and Amenities (or break it with intermediate entity)
  • @OneToOne between Guest and Passport

Performance 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)