Configuring Hibernate Mappings with Annotations
Hibernate supports two primary methods for configuring object-relational mappings: XML-based configuration and annotation-based configuration. This article focuses on the annotation approach, which offers a more concise and integrated solution. Startnig from Hibernate 4, annotation support is included by default; for Hibernate 3, you need to add the annotation JARs separately.
Basic Entity Mapping
To map a simple entity, use annotations to define the database table and fields. Here's an example with a Customer class:
@Entity
@Table(name = "customer_table")
public class Customer {
private Integer customerId;
private String customerName;
private String email;
private LocalDate signupDate;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "customer_id")
public Integer getCustomerId() {
return customerId;
}
public void setCustomerId(Integer customerId) {
this.customerId = customerId;
}
@Column(name = "customer_name", length = 100, nullable = false)
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
@Column(name = "email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Column(name = "signup_date")
public LocalDate getSignupDate() {
return signupDate;
}
public void setSignupDate(LocalDate signupDate) {
this.signupDate = signupDate;
}
}
In your hibernate.cfg.xml, include the entity class:
<mapping class="com.example.model.Customer"/>
One-to-Many Relationship
For a one-to-many relasionship, such as between Department and Employee, define the mapping as follows:
Department class:
@Entity
@Table(name = "department")
public class Department {
private Integer deptId;
private String deptName;
private Set<Employee> employees = new HashSet<>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "dept_id")
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
@Column(name = "dept_name")
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
@OneToMany(mappedBy = "department")
@LazyCollection(LazyCollectionOption.EXTRA)
public Set<Employee> getEmployees() {
return employees;
}
public void setEmployees(Set<Employee> employees) {
this.employees = employees;
}
}
Employee class:
@Entity
@Table(name = "employee")
public class Employee {
private Integer empId;
private String empName;
private Department department;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "emp_id")
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
@Column(name = "emp_name")
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "dept_id")
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}
One-to-One Relationship
For a one-to-one relationship, such as between User and Profile, map it like this:
User class:
@Entity
@Table(name = "user_table")
public class User {
private Integer userId;
private String userName;
private Profile profile;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
@Column(name = "user_name")
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@OneToOne(mappedBy = "user")
public Profile getProfile() {
return profile;
}
public void setProfile(Profile profile) {
this.profile = profile;
}
}
Profile class:
@Entity
@Table(name = "profile")
public class Profile {
private Integer profileId;
private String bio;
private User user;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "profile_id")
public Integer getProfileId() {
return profileId;
}
public void setProfileId(Integer profileId) {
this.profileId = profileId;
}
@Column(name = "bio")
public String getBio() {
return bio;
}
public void setBio(String bio) {
this.bio = bio;
}
@OneToOne
@JoinColumn(name = "user_id")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Many-to-Many Relationship
For a many-to-many relationship, such as between Product and Category, you can use a join table:
Product class:
@Entity
@Table(name = "product")
public class Product {
private Integer productId;
private String productName;
private Set<Category> categories = new HashSet<>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "product_id")
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
@Column(name = "product_name")
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
@ManyToMany
@JoinTable(name = "product_category",
joinColumns = @JoinColumn(name = "product_id"),
inverseJoinColumns = @JoinColumn(name = "category_id"))
public Set<Category> getCategories() {
return categories;
}
public void setCategories(Set<Category> categories) {
this.categories = categories;
}
}
Category class:
@Entity
@Table(name = "category")
public class Category {
private Integer categoryId;
private String categoryName;
private Set<Product> products = new HashSet<>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "category_id")
public Integer getCategoryId() {
return categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
@Column(name = "category_name")
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
@ManyToMany(mappedBy = "categories")
public Set<Product> getProducts() {
return products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
}
Alternatively, you can decompose a many-to-many into two one-to-many relationships using an intermediate entity, such as Order and Item with OrderItem:
Order class:
@Entity
@Table(name = "orders")
public class Order {
private Integer orderId;
private String orderNumber;
private Set<OrderItem> orderItems = new HashSet<>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "order_id")
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
@Column(name = "order_number")
public String getOrderNumber() {
return orderNumber;
}
public void setOrderNumber(String orderNumber) {
this.orderNumber = orderNumber;
}
@OneToMany(mappedBy = "order")
public Set<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(Set<OrderItem> orderItems) {
this.orderItems = orderItems;
}
}
Item class:
@Entity
@Table(name = "item")
public class Item {
private Integer itemId;
private String itemName;
private Set<OrderItem> orderItems = new HashSet<>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "item_id")
public Integer getItemId() {
return itemId;
}
public void setItemId(Integer itemId) {
this.itemId = itemId;
}
@Column(name = "item_name")
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
@OneToMany(mappedBy = "item")
public Set<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(Set<OrderItem> orderItems) {
this.orderItems = orderItems;
}
}
OrderItem class:
@Entity
@Table(name = "order_item")
public class OrderItem {
private Integer orderItemId;
private Integer quantity;
private Order order;
private Item item;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "order_item_id")
public Integer getOrderItemId() {
return orderItemId;
}
public void setOrderItemId(Integer orderItemId) {
this.orderItemId = orderItemId;
}
@Column(name = "quantity")
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
@ManyToOne
@JoinColumn(name = "order_id")
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
@ManyToOne
@JoinColumn(name = "item_id")
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
}
When insetring data, save the entity that does not define the foreign key first, then the one that does. For example, in a one-to-one relationship:
User user = new User();
user.setUserName("john_doe");
session.save(user);
Profile profile = new Profile();
profile.setBio("Software developer");
profile.setUser(user);
session.save(profile);