Thursday, August 25, 2011

Hibernate annotations one-to-many and component

  This example is based on my previous post [Hibernate Annotations Example]. Previously an entity car was modeled to the database. Now in addition to that, an entity, car sale is to be mapped to the database, which has a one-to-many relationship with the entity, car. Moreover the address of the car sale is considered as a component of the same. Therefore we need to have two more modelling classes 'Sale' and 'Address'.
   The hibernate.cfg.xml file needs to be updated with 2 mapping elements (sub-elements of session-factory),
       <mapping class="com.shyarmal.hibernate.Sale"/>
   <mapping class="com.shyarmal.hibernate.Address"/>

   The only change done to the class, 'Car' from the previous example is changing the column name 'id' of the database table, 'cars' to 'car_id' .
===================================================================

package com.shyarmal.hibernate;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="cars")
public class Car {

    private Long id;
    private String make;
    private String brand;
    private String model;
    private double capacity;
    private double price;

    @Id
    @GeneratedValue
    @Column(name = "car_id")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getMake() {
        return make;
    }

    public void setMake(String make) {
        this.make = make;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public double getCapacity() {
        return capacity;
    }

    public void setCapacity(double capacity) {
        this.capacity = capacity;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

}

===================================================================

   An instance of the class, 'Address' is supposed to hold the address of a sale. So 'Sale' is in uni-directional association with 'Address'.  i.e. 'Address' is a component of Sale. Therefore it's annotated with  @Embeddable.
===================================================================

package com.shyarmal.hibernate;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Table;

@Embeddable
public class Address {

    private String number;
    private String street;
    private String city;

    public Address() {
       
    }
   
    public Address(String number, String street, String city) {
        this.number = number;
        this.street = street;
        this.city = city;
    }
   
    @Column(name = "no", nullable = false, length = 10)
    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Column(name = "street", nullable = false, length = 50)
    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    @Column(name = "city", nullable = false, length = 50)
    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

}

===================================================================

   Records of the car sale will be saved in a table named, 'car_sale' in the mysql database. The address filed of Sale is annotated with  @Embedded, so that all the fields of the 'Address' instance set to 'Sale' will be saved in the table 'car_sale'. This is known as component mapping.
   'Sale' is having a one-to-many relationship with 'Car' and hence it has a set of 'Car' instances whose getter is annotated with @OneToMany(cascade = CascadeType.ALL). Further any change made to a 'sale' record will be cascaded to it's 'car' records. A joining table, 'sales_car_join' is used to link the cars with the sales (name attribute of @JoinTable) in this example. The 'joinColumns' attribute of @JoinTable specifies which field of 'Sale' should be used in the relationship and 'inverseJoinColumns' the field of 'Car'.
===================================================================

package com.shyarmal.hibernate;

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "car_sale")
public class Sale {

    private Long id;
    private Set<Car> cars;
    private Address address;
    private String name;

    @Id
    @GeneratedValue
    @Column(name = "sale_id")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @OneToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "sales_car_join",
            joinColumns = {@JoinColumn(name = "sale_id")},
            inverseJoinColumns = {@JoinColumn(name = "car_id")})
    public Set<Car> getCars() {
        return cars;
    }

    public void setCars(Set<Car> cars) {
        this.cars = cars;
    }

    @Embedded
    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Column(name = "name", nullable = false)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

===================================================================

The following code saves a 'Sale' instance to the mysql database. Eventually a car_sale record, two cars records and two sales_car_join records will be saved in the database.
===================================================================

package com.shyarmal;

import java.util.HashSet;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.shyarmal.hibernate.Address;
import com.shyarmal.hibernate.Car;
import com.shyarmal.hibernate.HibernateUtil;
import com.shyarmal.hibernate.Sale;

public class Main {

    public static void main(String[] args) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        Transaction transaction = session.beginTransaction();
        session.save(getSale());
        transaction.commit();
    }
   
    private static Sale getSale() {
        Sale sale = new Sale();
        sale.setAddress(new Address("7832", "Woxhall", "Union Place"));
        sale.setName("xyz");
        sale.setCars(getCarSet());
        return sale;
    }
   
    private static Set<Car> getCarSet() {
        Set<Car> carSet = new HashSet<Car>();
       
        Car car1 = new Car();
        car1.setBrand("Vitz");
        car1.setMake("Toyota ");
        car1.setModel("2009");
        car1.setCapacity(20.4);
        car1.setPrice(30000000);
        carSet.add(car1);
       
        Car car2 = new Car();
        car2.setBrand("Camry");
        car2.setMake("Toyota ");
        car2.setModel("2011");
        car2.setCapacity(20.4);
        car2.setPrice(45000000);
        carSet.add(car2);
       
        return carSet;
    }
}


thanks,
Shyarmal.

No comments:

Post a Comment