Entity mapping
Spring Boot এর সাথে JPA (Java Persistence API) ব্যবহার করলে আমরা Entity ক্লাসের মাধ্যমে ডাটাবেজ টেবিলের সাথে কাজ করি। এই Entity ক্লাসগুলোর মধ্যে সম্পর্ক (Relationship) স্থাপন করাই মূলত Entity Mapping। Entity mapping আমাদের কোডকে আরও object-oriented, reusable, এবং database-independent করে তোলে।
Entity কী?
Entity হলো এমন একটি জাভা ক্লাস, যা ডাটাবেজের একটি টেবিলকে রিপ্রেজেন্ট করে। প্রতিটি Entity এর অবজেক্ট টেবিলের একটি row (record) এর সমান।
উদাহরণ:
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
}
এখানে User ক্লাসটি ডাটাবেজের users টেবিলের সাথে ম্যাপ হয়েছে।
Entity Mapping এর ধরন
Entity mapping মূলত চার ধরনের সম্পর্ক (Relationship) নিয়ে কাজ করে
- One-to-One
- One-to-Many
- Many-to-One
- Many-to-Many
চলো একে একে দেখি।
One-to-One Relationship
একটি টেবিলের একটি রেকর্ড অন্য একটি টেবিলের একটি রেকর্ডের সাথে সম্পর্কিত।
উদাহরণ:
প্রতিটি ইউজারের একটি করে Address থাকে।
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
}
@Entity
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String city;
private String country;
}
এখানে @OneToOne সম্পর্ক তৈরি করছে, এবং @JoinColumn এর মাধ্যমে foreign key নির্ধারণ করছে।
One-to-Many Relationship
একজন ইউজারের একাধিক অর্ডার থাকতে পারে।
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Order> orders = new ArrayList<>();
}
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String product;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
এখানে User এর একাধিক Order থাকতে পারে,
কিন্তু প্রতিটি Order শুধুমাত্র একটি User এর অন্তর্ভুক্ত।
Many-to-One Relationship
উপরের উদাহরণেই দেখা যাচ্ছে,
Order entity থেকে দেখলে, এটি একটি Many-to-One সম্পর্ক —
কারণ অনেক অর্ডার এক ইউজারের হতে পারে।
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
এটি bidirectional সম্পর্কের দ্বিতীয় দিক।
Many-to-Many Relationship
একজন ছাত্র অনেক কোর্সে ভর্তি হতে পারে,
আবার একটি কোর্সে অনেক ছাত্র থাকতে পারে।
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private List<Course> courses = new ArrayList<>();
}
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToMany(mappedBy = "courses")
private List<Student> students = new ArrayList<>();
}
Hibernate এখানে স্বয়ংক্রিয়ভাবে student_course নামে একটি join table তৈরি করবে।
CascadeType Explained
cascade attribute বলে দেয়, parent entity এর অপারেশন child entity তে propagate হবে কি না।
| Cascade Type | ব্যাখ্যা |
|---|---|
PERSIST |
Parent save হলে child ও save হবে |
MERGE |
Parent merge হলে child ও merge হবে |
REMOVE |
Parent delete হলে child ও delete হবে |
REFRESH |
Parent refresh হলে child refresh হবে |
ALL |
উপরের সবগুলো প্রযোজ্য হবে |
FetchType Explained
FetchType বলে দেয় সম্পর্কিত entity কবে লোড হবে 👇
| Fetch Type | ব্যাখ্যা |
|---|---|
EAGER |
Parent লোড হলে সাথে child entity লোড হয় |
LAZY |
Child entity লোড হয় প্রয়োজন হলে (on-demand) |
ডিফল্টভাবে:
@OneToOne এবং @ManyToOne → EAGER
@OneToMany এবং @ManyToMany → LAZY
উদাহরণ: Bi-directional Relationship
@Entity
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "author")
private List<Book> books = new ArrayList<>();
}
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToOne
@JoinColumn(name = "author_id")
private Author author;
}
এখন Author থেকে Book ও Book থেকে Author — দুই দিক দিয়েই relationship অ্যাক্সেস করা যাবে।
Entity Mapping Best Practices
- প্রতিটি entity তে অবশ্যই @Id এবং unique identifier থাকতে হবে।
- সবসময় LAZY fetch ব্যবহার করো performance এর জন্য।
- Cascading শুধুমাত্র যেখানে প্রয়োজন সেখানে প্রয়োগ করো।
- Bidirectional mapping করলে দুই দিকেই reference রাখতে ভুলো না।- equals() এবং hashCode() entity তে implement করার সময় শুধুমাত্র ID ব্যবহার করো।- @ToString (Lombok) ব্যবহার করলে relationship field exclude করো, না হলে recursive loop হতে পারে।
Practical Example: User ↔ Role Mapping
@Entity
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "user_role",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();
}
এখানে এক ইউজারের একাধিক রোল থাকতে পারে,
আবার একটি রোল অনেক ইউজারের হতে পারে।