Powered By Blogger

Saturday, September 17, 2011

Hibernate with JPA Annotations - OneToOne

 This example illustrates a one-to-one mapping in Hibernate using JPA annotations. The illustration is about a case where a driver has one driving license. Here the license details will be saved to a database table by the name 'license' and that of driver to 'driver'. I'm only discussing the OneToOne mapping here. [For other basic information, refer to Hinernate Annotations Example].
  The mappings of the classes should be in the hibernate.cfg.xml file
        <mapping class="com.shyarmal.hibernate.Driver"/>
        <mapping class="com.shyarmal.hibernate.License"/>

My License class.
===============================================================

package com.shyarmal.hibernate;

import java.util.Date;

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

@Entity
@Table(name = "license")
public class License {

    private Long id;
    private Date issueDate;
    private String country;
    private String category;

    private License() {
    }
   
    public License(Date issueDate, String country, String category) {
        this.issueDate = issueDate;
        this.country = country;
        this.category = category;
    }

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

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

    @Column(name = "issue_date", columnDefinition = "timestamp")
    public Date getIssueDate() {
        return issueDate;
    }

    public void setIssueDate(Date issueDate) {
        this.issueDate = issueDate;
    }

    @Column(name = "country")
    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    @Column(name = "category")
    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }
}
===============================================================

The Driver class should have an instance of the License class, if to form a one-to-one.
My Driver class
===============================================================

package com.shyarmal.hibernate;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name = "driver")
public class Driver {

    private Long id;
    private String name;
    private int age;
    private License license;

    private Driver() {
       
    }
   
    public Driver(String name, int age) {
        this.name = name;
        this.age = age;
    }
   
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @OneToOne(cascade = CascadeType.ALL)
    public License getLicense() {
        return license;
    }

    public void setLicense(License license) {
        this.license = license;
    }

}

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

@OneToOne:- This annotation is to make the link between the corresponding field of the annotated class to that intended to be related in one-to-one mapping. The CascadeType is set to ALL which will reflect any change in the 'driver' table to the 'license' table. That means, for an instance if a driver is deleted his license will also be deleted correspondingly.


thanks,
Shyarmal.

Thursday, September 15, 2011

Loop Break - Scala

Following example shows how to break out of a loop in Scala. Here the package, 'util.control.Breaks._' is imported and the foreach loop is enclosed in a 'breakable' block (to avoid a runtime exception caused by the break). In the example the loops breaks when n is 5.

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

package shyarmal.test.scala

import util.control.Breaks._

object ScalaBreak {

  def main(args: Array[String]) {

    val nums = 1 :: 2 :: 3 :: 4 :: 5 :: 6 :: 7 :: Nil
    breakable {
      nums.foreach(n => {
        if (n == 5)
          break
        println(n)
      })
    }

  }
}

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

The output: 1 2 3 4

thanks,
Shyarmal

Saturday, August 27, 2011

Hibernate Annotations with Collections (List)

Following class illustrates how to model a java.util.List in hibernate with annotations. The subjects that a student takes are given in a list. So the 'Student' class is having an instance of List of String's. This can only be used to model collections of Java built-in types.
 
package com.shyarmal.hibernate;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;

@Entity
public class Student {

    private Long id;
    private String college;
    private List<String> subjects;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }
   
    public void setId(Long id) {
        this.id = id;
    }

    @Column(name = "college")
    public String getCollege() {
        return college;
    }

    public void setCollege(String college) {
        this.college = college;
    }
   
    @ElementCollection(fetch = FetchType.LAZY)
    @JoinTable(name = "student_subjects",
       joinColumns = {@JoinColumn(name = "student_id")})
    public List<String> getSubjects() {
        return subjects;
    }

    public void setSubjects(List<String> subjects) {
        this.subjects = subjects;
    }
}


Annotations used to handle the scenario;
  • @ElementCollection:- Informs that the instance annotated should be considered as a Java collection type. The optional attribute 'fetch' may be given to stress how the collection should be loaded [either lazy (the default) or eager]
  • @JoinTable:- Used to explicitly specify the properties of the table which joins the collection data with the entity in concern. Name of the joining column also can be given, which links to the primary key of the entity. Inverse joining column attribute should not be specified in this case.

thanks,
Shyarmal.

Hibernate Inheritance with Annotations

 There are a few approaches to deal with inheritance in hibernate. The technique discussed in this post accommodates all in one table.
  I'm having an abstract class, 'Person' and two of it's subclasses, 'Student' and 'Employee'. Both 'Student' and 'Employee' information is to be stored in a single table, named 'person'.

==================================================================
package com.shyarmal.hibernate;

import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

@Entity
@Table(name = "person")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "person_type", discriminatorType = DiscriminatorType.STRING)
public abstract class Person {

    private Long id;
    protected String nic;
    protected int age;
    protected String name;
    protected char sex;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }
   
    public void setId(Long id) {
        this.id = id;
    }
   
    @Column(name = "nic", unique = true, nullable =false)
    public String getNic() {
        return nic;
    }

    public void setNic(String nic) {
        this.nic = nic;
    }

    @Column(name = "age")
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

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

    @Column(name = "gender", length = 2, nullable = false)
    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }
}

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

  First, we'll have a look at the 'Person' class. Here I'll only discuss what's done to accomplish inheritance [For other basic information, refer to Hinernate Annotations Example].  The annotation, @Inheritance denotes inheritance and there are subclasses of person to be mapped. Moreover all 'Person' instances will be available in a single database table, since the inheritance strategy used is  'InheritanceType.SINGLE_TABLE'.   
   @DiscriminatorColumn is mandatory in this approach. It forms a new column in the database with the name specified in the 'name' attribute. The discriminator column is used to Identify the type of the record (in our example where a record is of type 'Student' or 'Employee'). The attribute 'discriminatorType' states the type of the discriminator column.
   I have posted my 'Student' and 'Employee' classes below.

=================================================================== 
package com.shyarmal.hibernate;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;

@Entity
@DiscriminatorValue("student")
public class Student extends Person {

    private String college;
    private List<String> subjects;

    @Column(name = "college", nullable = false, columnDefinition = "varchar(20) default 'unknown'")
    public String getCollege() {
        return college;
    }

    public void setCollege(String college) {
        this.college = college;
    }
   
    @ElementCollection(fetch = FetchType.LAZY)
    @JoinTable(name = "student_subjects", joinColumns = {@JoinColumn(name = "person_id")})
    public List<String> getSubjects() {
        return subjects;
    }

    public void setSubjects(List<String> subjects) {
        this.subjects = subjects;
    }

    @Override
    public String toString() {
        return String.format("student: nic [%s], college [%s], name [%s], age [%d]", nic, college, name, age);
    }
}

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

package com.shyarmal.hibernate;

import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue("employee")
public class Employee extends Person {

    private String company;
    private double salary;

    @Column(name = "company", nullable = false, columnDefinition = "varchar(20) default 'unknown'")
    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    @Column(name = "salary", nullable = false, columnDefinition = "double(8, 2) default '0.0'")
    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return String.format("employee: nic [%s], company [%s], name [%s], age [%d]", nic, company, name, age);
    }
}
===================================================================

@DiscriminatorValue annotation should be present in the subclasses. The discriminator value is what's saved in the discriminator column, which was discussed above [in our example if an employee is saved the discriminator column will have the value 'employee' and for a student the value will be 'student']. Notice 'columnDefinition' attribute in @Column in subclasses. If a column is declared not to be nullable, then a default value for the corresponding field should be given as done in the example. If not hibernate does not create the table. 'Student' class has a list of subjects. The methodology used is described here.

Below is the hibernate.cfg.xml used.
=================================================================== 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="connection.url">jdbc:mysql://localhost/test</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="hbm2ddl.auto">create</property>
        <property name="connection.pool_size">1</property>
        <property name="current_session_context_class">thread</property>
        <mapping class="com.shyarmal.hibernate.Person"/>
        <mapping class="com.shyarmal.hibernate.Student"/>
        <mapping class="com.shyarmal.hibernate.Employee"/> 
    </session-factory>
</hibernate-configuration>


thanks,
Shyarmal.

Hibernate annotations with enums

    How enums can be dealt using annotations is described here. In the example there are two enums, 'Status' and 'Priority', which are instances of the class, 'Batch'. 'Batch' is a domain class.

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

package com.shyarmal.hibernate;

public enum Status {

    STARTED, SUSPENDED, FINISHED, ABANDON
}


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

package com.shyarmal.hibernate;

public enum Priority {

    HIGH, MEDIUM, LOW
}
===================================================================

   'Batch' is annotated as an entity and it's instances will be saved to a table called 'batch' in the database. @Enumerated annotation is used to mark a filed as an enum. Here the EnumType of 'Priority' is ORDINAL and hence an integer will be saved in the database which corresponds to it's actual value. Integers will be assigned to the enum values in the ascending order, starting with 0. As the EnumType of 'Status' is STRING, the values of it will be saved as varchar in the database.
===================================================================

package com.shyarmal.hibernate;

import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "batch")
public class Batch {

    private Long id;
    private Status status;
    private Priority priority;

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

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

    @Enumerated(value = EnumType.STRING)
    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    @Enumerated(value = EnumType.ORDINAL)
    public Priority getPriority() {
        return priority;
    }

    public void setPriority(Priority priority) {
        this.priority = priority;
    }

    @Override
    public String toString() {
        return String.format("batch: priority [%s], status [%s]", priority.name(), status.name());
    }

}

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

Following are some CRUD functions performed on 'Batch'.
===================================================================
// saving a batch
private static void save() {
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            Batch batch = new Batch();
            batch.setPriority(Priority.HIGH);
            batch.setStatus(Status.STARTED);
            session.save(batch);
            transaction.commit();
        } catch(Exception e) {
            transaction.rollback();
            e.printStackTrace();
        }
    }
   
// find one batch by the id.
private static void find() {
    Transaction transaction = null;
     try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         Batch batch = (Batch) session.get(Batch.class, new Long(1)); // batch with the id 1.
         transaction.commit();
     } catch(Exception e) {
         transaction.rollback();
         e.printStackTrace();
     }
}
   
// editing a batch 
private static void edit() {
     Transaction transaction = null;
      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         Batch batch = (Batch) session.get(Batch.class, new Long(1));
         batch.setPriority(Priority.LOW);
         batch.setStatus(Status.SUSPENDED);
         transaction.commit();
      } catch(Exception e) {
         transaction.rollback();
         e.printStackTrace();
      }
}
   
// deleting a batch
private static void delete() {
   Transaction transaction = null;
    try {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        transaction = session.beginTransaction();
        session.delete(session.get(Batch.class, new Long(1)));
        transaction.commit();
    } catch(Exception e) {
        transaction.rollback();
        e.printStackTrace();
     }
}

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

Hibernate configuration file used is below. Notice the mapping, '<mapping class="com.shyarmal.hibernate.Batch"/>'.
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="connection.url">jdbc:mysql://localhost/test</property>
        <property name="connection.username">danuka</property>
        <property name="connection.password">123</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="hbm2ddl.auto">create</property>
        <property name="connection.pool_size">1</property>
        <property name="current_session_context_class">thread</property>
        <mapping class="com.shyarmal.hibernate.Batch"/> 
    </session-factory>
</hibernate-configuration>

===================================================================
A sample record in the database.
mysql> select * from batch;
+----+----------+-------------+
| id | priority | status        |
+----+----------+-------------+
|  1 |        0 | FINISHED   |
+----+----------+-------------+
1 row in set (0.00 sec)


thanks,
Shyarmal.

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.