Professional Documents
Culture Documents
javabrains.koushik.org
What is ORM tool
• object relation mapping maps the gap between
object and relational database, which why it is
called object relational mapping
• used in database layer
• implements JPA (Java Persistence Api)
• Hibernate uses annotations which are
imported from javax.persistence.*
• class corresponds to a table and object
corresponds to row
Pain points in Hibernate
• Service method to create the model object - Use the hibernate API
The service method will have an instance of model object (and normally it will pass the model
object to a data layer which uses jdbc). Instead in hibernate the service method would pass the
object to the hibernate API. The method would use the hibernate API directly or pass it on to data
layer which uses the hibernate API. So it’s the hibernate API which does the save of the save of
model object.
• <property name="show_sql">true</property>
this will print out all the sql which hibernate generates
• <property name="hbm2ddl.auto">create</property>
• Create means that hibernate is goinf to drop and recreate the schema when it runs for the first time.
• <property name="hbm2ddl.auto">update</property>
• You want to retain the data that was created in the previous run then use update
Depending what we configure as model object it will create a DB schema that is required to save the model object.
If we pass an object and we ask hibernate to save the object if table is not available then hibernate will create the tables with all the
right columns to save all the member variables of the objects.
By leaving as create we don’t have to create the tables ourselves
<property name="show_sql">true</property>
• This setting prints out the SQl query in the console
> src> new > class> Give package name - org.javabrains.kaushik.dto > class name - UserDetails > finish
package org.javabrains.kaushik.dto;
import javax.persistence.Entity
import javax.persistence.Id
@Entity
public class UserDetails{
@Id
private int userId
private String name
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Go to configration file and specify the model class in the tag
<mapping class="org.javabrains.kaushik.dto.UserDetails" />
Creating a class that instantiates the objects of the UserDetails class
package org.koushik.hibernate
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernaqte.koushik.dto.UserDetails;
import org.hibernate.Session
• @Entity
• @Table (name=”USER_DETAILS”)
• public class UserDetails{
• @Id
• private int userId
@Transient
private String userName
@Basic
• private String address;
@Lob
• private String description;
@Temporal (TemporalType.Date)
• private Date joinedDate;
package org.koushik.hibernate
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernaqte.koushik.dto.UserDetails;
import org.hibernate.Session
public class HibernateTest{
public static void main(String args){
UserDetails user = new UserDetails();
user.setUserID(1);
user.setUserName("First User");
user.setAddress(“First User’s Address”);
user.setJoinedDate(new Date());
user.setDescription()”Description of user goes here”;
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(user); //object is saved
sesion.getTransation.commit(); //end the tansaction by getting the transaction and doing a commit
}
}
Retrieving objects using session.get
• @Id – it created a primary key column for this userId and then it denoted it as primary key.
Then you can use this primary key for fetching data. We can pass the values of primary key
to session.get and then we can get the object itself.
• @Id @GeneratedValue – is used while specifying a surrogate key which is a type of primary
key.
• @Id @GeneratedValue(strategy=GenerationType.AUTO)
• @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
• @Id @GeneratedValue(strategy=GenerationType.SEQUENCE)
• @Id @GeneratedValue(strategy=GenerationType.TABLES)
Primary Keys
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id
private int userId
private String userName
//generate getters and setters
}
}
Primary Key
package org.koushik.hibernate
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernaqte.koushik.dto.UserDetails;
import org.hibernate.Session
• Natural Key - Suppose in your application you have a column which has distinct
values and which you know is mandatory. Suppose you have a registration
application, you have people registering by giving email address, first name, last
name. Suppose your business rule dictates that every user needs to have an email
ID. Every user has to provide a distinct unique email id when they are registering.
In that case we can have the email address as a primary key. Such columns which
actually are there for a business reason but then you can assign one of them as a
primary key. Such keys and are called natural keys.
• Surrogate key
• You don’t know if any column can be marked as unique. You don’t have a column
that can be marked as unique or you anticipate that could change in future. Thus
you add a new column and the purpose of the column is to entirely act as a primary
key alone it does not have any business significance but you need to have a
separate column just for it to act as a key. In that case thats called a surrogate key.
It kind of having a SNO column column in front of your table. It does not server
any other purpose and it does not carry any data apart from the fact that it marking
out all the different rows as separate and its having a unique number for each.
Managing Natural Key
• Let’s look at how hibernate supports each
• The key that we are user here is userId. If userId is
specifically for the purpose of declaring a primary key and
it does not have a business use then it’s a surrogate key.
But if it has a business use and you know it’s a loginId for
e.g. and you are making loginid as primary key then that
would be a natural key because loginId is used for other
purpose
• If we are having a natural key it would make sense for us to
provide the value because it’s of business significance, we
need to know what the value is and we need to control it.
Managing Surrogate Key
• But, if it is a surrogate key then we can ask hibernate to do the job for us. It really does not matter what
the value will be. It can be last value+1, we need to make sure that it is unique, it has to be mandatory
and cannot be optional and cannot be null. These two things are something that hibernate can manage
for us. We can tell hibernate to generate a surrogate key for us. whenever we are using such a
surrogate key e.g. this userid happens to be a surrogate key (I have added this value here I but don’t
need it for any other reason apart from using it as an id). In that case we can ask hibernate to generate
this value for us every time we do an insert. I don’t have to create this id every time, I don’t have to
pass it to hibernate. Hibernate can automatically generate and manage the newly created object keys.
• No need to specify the userid: f I have to insert a new user then I have to set the username and
hibernate will take care of creating the right userid for me.
• If I have to supply the surrogate key myself, I have to look up what is the last surrogate key id that was
created. If there were 500 users and the last userid was inserted was 500 then I would add one to it and
then insert userid 501. So this is something that I don’t have to do if I use Hibernate’s help. Hibernate
will do that work and it will generate a primary key for me. I can use that functionality of hibernate by
specifying another annotation called @GeneratedValue
• @GeneratedValue – its asking hibernate to generate this value for me. I am not going to generate this
myself. Hibernate will look at the data type of this property which is an integer and it will generate an
integer for me and then it going to add that value. So I don’t have to pass the userid value like
user.setUserId(1) , I will only pass the user name and when I do a save its going to save the value.
• Its done a nextval(hibernate_sequence). Whats happening is Hibernate is maintain a sequence
internally and generating the userid depending on sequence. Hibernate gets the next value from
sequence and uses that value (which is userid) to insert userid.
@Id @GeneratedValue(strategy=GenerationType.AUTO)
• @Id @GeneratedValue(strategy=GenerationType.AUTO)
• AUTO – means that we will let hibernate make a decision as to what strategy to use
in order to come up with unique primary keys
• IDENTITY – hibernate will use identity columns. Identity columns is a feature in some
of the database . Its not a generic feature in all the databases. SQLserver and mysql
provideidentity col feature. If you are using those databases you can say
GenerationType.IDENTITY in which case hibernate is going to use that feature of DB
in order to come up with unique primary keys.
• SEQUENCE –uses the sequence object in the DB order to come up with unique key.
which is what is happeing here Its using a hibernate sequence object. SEQUENCE
object is something that you can have in the database in order to maintain
sequences. You can use that you can add sequence, when you say nexyval it
automatically pulls up the next value and updates the sequence, so that subsequent
nextvals pull up the next data. It something that databases manage by themselves.
You can use sequence to come up with unique values for primary key.
• TABLES – you can have a separate table and that table which will have a record of the
last used primary key so that you can increment it and get the next value. If you use
this table option Hibernate will use the table for generating the primary key
@GeneratedValue – for surrogate key
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue
private int userId
private String userName
//generate getters and setters
}
}
Demonstrating surrogate key usage
package org.koushik.hibernate
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernaqte.koushik.dto.UserDetails;
import org.hibernate.Session
public class HibernateTest{
public static void main(String args){
UserDetails user = new UserDetails();
user.setUserName("First User");
UserDetails user2 = new UserDetails();
User2.setUserName("Second User");
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(user); //object is saved
session.save(user2);
sesion.getTransation.commit();
session.close();
Value Types and Embedding Objects
• Currently we have assumed that the member variables inside the can
all go inside single columns
• What if one of these member variables were to be an object instead
of simple data type that can fit into a column and that object had
few member variables inside of them each of them having particular
values. How will you save that using Hibernate. What if one of them
were an Array, List, Set. How will we save that using Hibernate. That’s
what we will learn in this tutorial.
• Scenario 1 – User class instead of having an address String has an
address object.
• We will write a separate Address class and the Address class will have
Street, City, State, Pincode
• Our UserDetails class instead of having a simple String as an address
member variable it will have an instance of address object. How will
we save this
Value Types and Embedding Objects
Scenario 1 – User class instead of having an address String has an address object.
• As of now the simplest way to do this is to have each of these member variables of the address object inside
the user class also to have separate columns
• Now the user class has an address object and the address object has some member variables.
• We are going to treat the member variables of address object the same way as member variables as the user
class itself. We will assume that there is no address object its just Steet, City, State, Pin code are the four other
member variables of the user class itself. We would save it the way we would save four member variables.
Thus we are saying to have separate column for street, city ,state, pin. This is almost as if these member
variables are member variables of user class. It not as if there is another object and the member variables are
of that object. It is almost as if there is one class and these are flat member variables.
• This option works fine if the object inside the UserDetails class is a value object.
• When you are dealing with value objects you have a different approach versus when you are dealing with
entities itself. Well you can have an entity inside another entity. There is no stopping you from having say
another object here which is actually an entity but which is related to user object. You can have a member
variable which is another entity and that entity might have a meaning of its own and that happens to be inside
another entity.
• But that not the case when its come to address. Address does not have a meaning on its own. It has to be
associated with a user object otherwise there is no point of having an Address object. That’s what make an
address object a value object.
• This approach that we are going to take can be applied to value object.
Approach1 – treat the member variables of address object the same way as member variables as the user class itself
Entity and Value Object
• A value object has data and even that has to be saved in the database but it
does not have any meaning of itself and provides meaning to some other
object. E.g. the address object with street city state pinc ode values all
populate. The address object as of itself does not have any meaning. It an
address of a User class. Without having a user object just an address does
not makes sense. It purpose in life is to provide value to the user object. Its
does
• not have a meaning on its own
Create Address Class
Create a new address class
package org.kaushik.javabrains.dto
import javax.presistance.Embeddable
@Embeddable
public class Address{
private String street;
private String city;
private String pincode;
private String Street;
//generate gettersandsetters
}
Inoder to mark this as a valuetype and tell hibernate not to create a separate table for this I need
to use @Embeded. @Embeded which tells hibernate that this object needs to be embeddable
inside something else
Add Address Instance to UserDetails Class add annotation @Embedded
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username
@Embedded
private Address address;
package org.koushik.hibernate
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernaqte.koushik.dto.UserDetails;
import org.hibernate.Session;
• @Column(name=“column_name”)
The above annotation goes on top of the field whose
name you want to configure in the embeddable object
(Address object in this case)
• @AttributeOverride – this annotation goes on top of the
field whose name you want to override so that it does
not take the default name in the UserDetails
table(Company Address reference in the UserDetails
table.)
• Case: If you are embedding an object and that object
happens to be a primary key then you cannot use @Id
and @Embedded but we can use @EmbeddedID. This
annotation is for embedded objects as a primary key.
Configuring the Columns of Embedded Object in UserDetails Table
package org.kaushik.javabrains.dto
import javax.presistance.Embeddable
@Embeddable
• I have a requirement of having two address objects inside the same class.
Home address, office address. How would it work.
• We cannot have two columns in the same table with the same name.
• We can solve this overriding the default name when you are embedding.
• Now when I am embedding this home address, I don’t want this to take to
take Street_Name, I want it to have Home_Stree_Name. So I can override
the column names here so that it does not take the default.
• Second thing is if I have multiple such objects I can give unique names to
each of those objects so that there is no conflict. Then eacbe created for
this address object.
• How do i actually do the override. To override I use @AttributeOverride .
This helps me to reconfigure all the attributes that have been either
configured h of those objects can have a set of columns which are to here
or I can change the default behavior so that I can make it specific to my
needs and secondly I can make it distinct so that there is no overlap
between different objects.
@AttributeOverride
package org.javabrains.koushik.dto;
import javax.persistence.AttributeOverride
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username
@Embedded
@AttributeOverrides ({
@AttributeOverride (name=”street”, column=@Column(name=”HOME_STREET_NAME”)),
@AttributeOverride (name=”city”, column=@Column(name=”HOME_STREET_NAME”)),
@AttributeOverride (name=”state”, column=@Column(name=”HOME_STREET_NAME”)),
@AttributeOverride (name=”pincode”, column=@Column(name=”HOME_STREET_NAME”))
})
private Address homeAddress;
@Embedded
private Address officeAddress;
//generate the getters and setters
}
main class
package org.koushik.hibernate
import org.hibernaqte.koushik.dto.UserDetails;
import org.hibernate.Session
public class HibernateTest{
public static void main(String args){
UserDetails user = new UserDetails();
user.setUserName("First User");
Address addr = new Address();
addr.setStreet(“Street Name”);
addr.setCity(“City Name”);
user.setHomeAddress(addr);
Address addr2 = new Address();
addr.setStreet(“Second Street Name”);
addr.setCity(“Second City Name”);
user.setOfficeAddress(addr2)
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(user); //object is saved
sesion.getTransation.commit();
session.close();
}
}
Special Case
• There is one special case where this userId the Primary Key of this model object
can itself be an embedded object.
• Let’s say I have an object which has first_name, last_name, soc_scurity_no,
login_id. A combination of all those is a primary key. Assume that we have few
member variables which put together forms a primary key e.g. userName, userId.
• We can use @Embedded but it would not work with @Id.
• we can use @EmbeddedID. This annotation is for embedded objects as a primary
key.
• In that case hibernate will treat a combination of all the member variables of the
objects as the primary key and If there is any repetition in all the values being same
for two different records. That’s when hibernate says that it not allowed. The object
itself and the comibnation of all the member variables has to be unique.
• If you are embedding an object and that object happens to be a primary key then
you cannot use @Id and @Embedded but we can use @EmbeddedID.
@EmbeddedId
package org.javabrains.koushik.dto;
import javax.persistence.AttributeOverride
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@EmbeddedId
private loginName userId;
private String username
@Embedded
private Address officeAddress;
//generate the getters and setters
}
Saving Collections
• Having Collection of Objects in our entity class and persisting it in a separate table
• I want a collection of List of Address to be a member variable of the UserDetails class.
• I want a collection to be a member variable of the UserDetails class. Use Case – I want to
keep a track of all the addresses that the particular user has lived in over the years. I have
a list of addresses and I don’t know how many they will be so I cannot instantiate them
statically.
• Now we can have collections and hibernate does provides support for that. But lets take a
minute to think how this would work. If it’s a fixed number of objects well it makes sense
we can have fixed number of columns. Say we had Home Address and we had separate
column for them. Once that created that would do. But now I do not know how many
address objects I would be having . I could have 1, or 100. How would you have handled
when you designed the table. You would probably create a different table for the address
data and you would have probably reference the user. e.g. I have userid1 I have 5 address
for this user, I will insert 5 records for this user in a separate table called address table and
each of those 5 records will have userid1 associated with it as a foreign key.
• So will create a collection of addresses inside the UserDetails entity class and we will
instantiate it and we will see how hibernate deals with this.
• We will start with a set.
• @ElementCollection – This makes Hibernate know that this has to be treated as a
collection and should not be embedded as a table but as a separate table.
• Also Address is marked as @Embeddable
Creating a Collection inside the UserDetails Entity Class
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username
@ElementCollection
@JoinTable(name=”USER_ADDRESS”)
private Set<Address> listOfAddresses = new HastSet();
//NOTE: I cannot use implementation while we are declaring the set
• First thing is the name of the table. Hibernate has given this name for us. Its Classname_memberVariable i.e.
UserDetails_ListOfAddresses.
• I want to Tweak this as it’s not a user friendly name. I want to have the name as User_Address.
• All I do is use the annotation @JoinTable(name=”USER_ADDRESS”)
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username
@ElementCollection
@JoinTable (name=”USER_ADDRESS”, joinColumns=@JoinColumns(name=”USER_ID”)).
private Set<Address> listOfAddresses = new HastSet();
//NOTE: I cannot use implementation while we are declaring the set
• I want to define an index or an ID for the table User_Address i.e. I want to define an ID for a collection inside your entity class. In
order to have an index column I need to have a datatype that supports index. I cannot use a HashSet because there is no index
supported in the hash set.
• To do that I would need to change the Collection declaration from Set to ArrayList. Because you have indexes in ArrayList or Array
• Also I need to define the primary key configuration in the UserDetails class – use annotation @CollectionId.
This annotationis unique in a sense that it is not a JPA annotation but imported from org.hibernate.annotations.CollectionId
• Note: that the ID is not present in the Address class. So I cannot set the ID and it has to be auto generated. In order for the Id to be
auto generated I define a generator which is hilo(type of generator). Once I define a generator I can use it in many places. I use
this generator in @CollectionID in order to generate the primary key. Here the primary key will be ADDRESS_ID
• All these are hibernate generators
Define an Index or Id for Join table USER_ADDRESS mentioned in Previous Slide
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username
@ElementCollection
@JoinTable(name=”USER_ADDRESS”, joinColumns=joinColumn(name=”USER_ID”))
@GenericGenerator(name=”hilo-gen”, strategy=”hilo”)
@CollectionId (columns={@Column(name=”ADDRESS_ID”)} , generator=”hilo-gen”, type=@Type(type=”long”))
private Collection<Address> listOfAddresses = new ArrayList();
//generate getters and setters
}
main class
package org.koushik.hibernate
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernaqte.koushik.dto.UserDetails;
import org.hibernate.Session
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username
@ElementCollection
@JoinTable(name=”USER_ADDRESS”, joinColumns=joinColumn(name=”USER_ID”))
private Collection<Address> listOfAddresses = new ArrayList();
//NOTE: I cannot use implementation while we are declaring the set
• To answer this question we will have to look at Fetch Strategy – Hibernate employs a strategy to solve this
problem. If you want to use just the user information you can ask hibernate not to pull up all the address
information. Infact that is the default behavior of hibernate unless you configure it otherwise.
• If I do a session.get(UserDetails.class, 1) it is not pulling up the list of addresses as well even though the user
object has list of addresses here. If you look at the state of User Object when the below line gets executed.
• user=(userDetails)session.get(UserDetails.class, 1);
• You will see that the addresslist is not initiated
• However the moment I run the getter method user.getListOfAddresses, that’s when hibernate goes and runs
another query to the DB and fetches the listOfAddresses.
• Now why does it do this way and how does it do this.
• Why – it you are just interested in user data. Say this user has few other info inside user details like phone
number, etc, and you are interested only that then there is no point in fetching the list ofaddresses. So you fetch
the list of addresses only when you are accessing the list of addresses. So the first time you use this getter it
would fetch the list of addresses.
• So it’s more efficient, doesn’t just pull up all the data that’s there. Say my UserDetails has 5 such lists like this
and each such list has 100 objects inside it. It’s going to take forever to get one object while I am just interested
in a name. Bec its going to pull all those list and all the data associated with the list and that’s going to be in
vain if you are not using it. So the why is fairly clear. You get it only when you use it. This kind of strategy is
called Lazy Initialization in Hibernate
Lazy/Eager Initialization
• Lazy Initialization – means that you do not initialize the entire
object, you only initialize the first level member variables of the
object. Then you initialize the list only when you access it.
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username
@ElementCollection (fetch = FetchType.EAGER);
@JoinTable(name=”USER_ADDRESS”, joinColumns=joinColumn(name=”USER_ID”))
private Collection<Address> listOfAddresses = new ArrayList();
//NOTE: I cannot use implementation while we are declaring the set
• The last few tutorials we have been looking at objects inside another object scenario. We have
explored a couple of scenarios there with one object being the entity and the object inside the
entity being value type. We saw how we could use hibernate to save those objects if there is one
instance of value type inside the entity we also looked at what if there is a collection of value type
inside the entity
• In this tutorial we will look at what happens if there is “One Entity inside another entity”
• This is what we have done so far. We have UserDetails Entity and inside that we have an element
collection of Address. Address is not an entity it’s a value type. We have looked at how to use
Hibernate to persist this entity if this address was just a single instance and also if it were a
collection.
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username
@OneToOne
private Vehicle vehicle
//generate getters and setters
}
Associating the Vehicle with the UserDetails class in the main method
• Now, we can instantiate the Vehicle class in the main class
public class HibernateTest{
public static void main(String args){
UserDetails user = new UserDetails();
user.setUserName("First User");
Vehicle vehicle = new Vehicle();
vehicle.setVehicleName(“Car”);
user.setVehicle(vehicle);
@Entity
public class Vehicle{
@ID @GeneratedValue
private int vehicleId;
private String vehicleName;
public int getVehicleId() {
return vehicleId;
}
public void setVehicleId(int vehicleId) {
this.vehicleId = vehicleId;
}
public String getVehicleName() {
return vehicleName;
}
public void setVehicleName(String vehicleName) {
this.vehicleName = vehicleName;
}
}
Mapping the Entity class in hibernate.cfg.xml
<session-factory>
<! -- Database connection settings -- >
<property name=”connection.driver_class”>org.h2.Driver</property>
<property name=”connection.url”>jdbc:h2:mem:db1; DB_CLOSE_DELAY=-1; </property>
<property name=”connection.username”>sa</property>
<property name=”connection.password”></property>
<! -- JDBC Connection Pool (Use the built in ) -- >
<property name=”connection.pool_size”>1</property>
<! -- SQL Dialect -- >
<property name=”dialect”>org.hibernate.Dialect.H2Dialect</property>
<! - - Disable the second level cache -- >
<property name=”cache.provider_class”>org.hibernate.provider.NoCacheProvider</property>
<! - - Echo all SQL to stdout -- >
<property name=”show_sql”>true</property>
Note: hibernate will print out all the SQL which it will generate
<! - - Drop and recreate the database schema on startup -- >
<property name=”show_sql”>true</property>
<! – Name the annotated entity class -- >
<mapping class="org.javabrains.kaushik.dto.UserDetails" />
<mapping class="org.javabrains.kaushik.dto.Vehicle" />
</session-factory>
Using @OneToMany in UserDetails class
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username;
@OneToMany
private Collection<Vehicle> vehicle = new ArrayList<Vehicle>();
//generate getters and setters
}
Adding the Vehicle to the collection in the main class
package org.koushik.hibernate
public class HibernateTest{
public static void main(String args){
UserDetails user = new UserDetails();
user.setUserName("First User");
Vehicle vehicle = new Vehicle();
vehicle.setVehicleName(“Car”);
Vehicle vehicle2 = new Vehicle();
Vehicle2.setVehicleName(“Jeep”);
user.getVehicle().add(vehicle);
user.getVehicle().add(vehicle2);
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(user); //object is saved
session.save(vehicle);
session.save(vehicle2);
sesion.getTransation.commit();
session.close();
}
}
table structure
• Three separate tables are created
• 1.USER_DETAILS
• 2. VEHICLE
• 3. USER_DETAILS_VEHICLE
• NOTE: Neither the USER_DETAILS has information about the
VEHICLE
• Nor the VEHICLE has information about the USER_DETAILS
• Instead hibernate creates the table USER_DETAILS_VEHICLE
and it has both the IDs i.e. USER_DETAILS_UserId and VEHICLE
_vehicleId of the above mention tables i.e. USER_DETAILS
• and VEHICLE
Now I can configure the JOIN_TABLE and the JOIN_COLUMN
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username;
@OneToMany
@JoinTable(name=”USER_VEHICLE”, joinColumns=@joinColumn(name=”USER_ID”),
inverseJoinColumns=@JoinColumn(name=VEHICLE_ID))
private Collection<Vehicle> vehicle = new ArrayList<Vehicle>();
//generate getters andtter s
}
}
Many to one Mapping
• There is one other way to represent one-to-many or a many-to-one relationship and that
is that the object on the many side of the relationship has a reference to the other object.
Now my User table cannot have a column for vehicle id bec one user can have multiple
vehicles. But the vehicle table can have a userId col bec any vehicle will have only one
user. It’s a many to one as far as the vehicle side of the relationship is concerned. So I can
have a userid col in my vehicle table and I can do the mapping there itself without having
a separate table which has the mapping for the user and the vehicle id. So in this tutorial
we will have a quick look at that
• I need to say that Vehicle class needs to have a mapping of that relationship
• I go to the UserDetails class and for the annotation @OneToMany I have a property
called mappedBy which says where want the mapping to happen.
• @OneToMany(mappedBy=“user”)
• Then I will go to Vehicle class and under @ManyToOne, I will specify the
@JoinColumn(name=USER_ID). So I am naming the join column that I am creating inside
the Vehicle table itself. So once we putting this annotation hibernate knows that the
mapping is for this user and the join column is in the Vehicle table. So instead of creating a
new table it will create a column inside the Vehicle table and it will have the id of the user
saved here
• Instead of mapping the USER_ID with VEHICLE_ID in a separate table hibernate inserts the
User_ID in the Vehicle table and does not create a new table
UserDetails class with one-to-many relationship
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username;
@OneToMany(mappedBy=“user”)
private Collection<Vehicle> vehicle = new ArrayList<Vehicle>();
// generate getters and setters
}
Vehicle class with many-to-one relationship
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
public class Vehicle{
@ID @GeneratedValue
private int vehicleId;
private String vehicleName;
@ManyToOne
@JoinColumn(name=USER_ID)
private UserDetails user;
//generate getters and setters
}
Many to Many
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username;
@ManyToMany
private Collection<Vehicle> vehicle = new ArrayList<Vehicle>();
//generate getter and setters
}
Vehicle class for many to many
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
public class Vehicle{
@ID @GeneratedValue
private int vehicleId;
private String vehicleName;
@ManyToMany
private Collection<UserDetails> userList = new ArrayList();
//generate getters and setters
}
Test Class for many to many
package org.koushik.hibernate
import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration;
import org.hibernaqte.koushik.dto.UserDetails;
import org.hibernate.Session
public class HibernateTest{
public static void main(String args){
UserDetails user = new UserDetails();
user.setUserName("First User");
• There are a few concepts which are common across all these three combinations and we will
look at these concepts in the next tutorial
Vehicle class with @MappedBy to prevent multiple mappings. The mapping
happens for the class not having @MappedBy
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
public class Vehicle{
@ID @GeneratedValue
private int vehicleId;
private String vehicleName;
@ManyToMany(mappedBy=“vehicle”)
private Collection<UserDetails> userList = new ArrayList();
//generate getters and setters
}
Specifying @JoinColumn inside @JoinTable
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username;
@ManyToMany
@JoinTable(name=”USER_VEHICLE”, joinColumns=@joinColumn(name=”USER_ID”),
inverseJoinColumns=@JoinColumn(name=VEHICLE_ID))
@Entity
public class Vehicle{
@ID @GeneratedValue
private int vehicleId;
private String vehicleName;
@ManyToOne
@NotFound(action=NotFoundAction.IGNORE)
private UserDetails user;
//generate getters and setters
}
@NotFound
• Assume that this vehicle is not having an owner i.e. this vehicle is not yet
rented/purchased so there is no user for this vehicle. So now what would happen if
you had a many to one association here and say you had getters and setters for
getUser() and setUser(). Now image if your code would get the vehicle and would
try to do a getUser()
• Imagine that your code would try to do a get vehicle and then try to do a getUser()
and there was no association for this vehicle in the user mapping, say there is no
user for this vehicle, then hibernate would throw an exception. It would say hey I
don’t have a user for this vehicle so a getUser() for a vehicle object which does not
have a user would throw an exception
• So there is a way in which we can suppress this exception so that hibernate does
not come with an error every time data is not there and if it is common situation
for data not be present at all time then you can prevent the these exceptions that’s
coming up by using the annotation @NotFound(action=NotFoundAction.IGNORE)
• This is imported from org.hibernate.annotations
• So if your user is not found you are telling hibernate to just ignore it and not throw
an exception
HibernateCollections
• The problem is If you have a huge list of vehicle objects you need to do a session.save() for all of them, which is
a pain.
• This is what we want to avoid by using a Cascade
Cascade
• So what I do is in the UserDetails wherever I have this reference @OneToMany. I will have to tell hibernate that
I do not want to save each and every object here. If you come across this collection and you have unsaved
objects when I am doing a save for this user class go ahead and save all the objects in the collection as well.
@OneToMany(Cascade=CascadeType.PERSIST)
• CascadeType.PERSIST tells hibernate that if you see any new entity inside this vehicle collection which has not
been saved when the user is being saved then go ahead and save them as well.
• In the main class instead of session.save(user) , we will call another method of session called session.persist(user)
• Persist kind of does the same thing what a save does but there are a few differences and this is something we will
explore in upcoming tutorials. But for now just make this change. This change session.persist() ties in with
@OneToMany(Cascade=CascadeType.PERSIST)
• So whenever persist happens cascade needs to happen.
• That ensures that this user is persisted
• If you want all the operations to happen cascaded you can choose. Instead of specify each and every operation
you can say cascasde everyting.
• @OneToMany(Cascade=CascadeType.ALL)
•
• CascadeType.REMOVE – which does a cascade for delete operation
• CascadeType.MERGE – explore later
• CascadeType.DETACH - explore later
• CascadeType.PERSIST - explore later
• CascadeType.REFRESH- explore later
using @OneToMany(Cascade=CascadeType.PERSIST)in UserDetails class
package org.javabrains.koushik.dto;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue
import java.util.Collection;
import java.util.ArrayList;
import org.hibernate.annotations.Collectionid;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
@Entity
@Table (name="USER_DETAILS")
public class UserDetails{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int userId
private String username;
@OneToMany(Cascade=CascadeType.PERSIST)
private Collection<Vehicle> vehicle = new ArrayList<Vehicle>();
//generate getters and setters
}
Vehicle class used in one to many
@Entity
public class Vehicle{
@ID @GeneratedValue
private int vehicleId;
private String vehicleName;
public int getVehicleId() {
return vehicleId;
}
public void setVehicleId(int vehicleId) {
this.vehicleId = vehicleId;
}
public String getVehicleName() {
return vehicleName;
}
public void setVehicleName(String vehicleName) {
this.vehicleName = vehicleName;
}
}
using session.persists(user) in the main class
package org.koushik.hibernate
import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration;
import org.hibernaqte.koushik.dto.UserDetails; import org.hibernate.Session
public class HibernateTest{
public static void main(String args){
UserDetails user = new UserDetails();
user.setUserName("First User");
vehicle vehicle = new Vehicle();
vehicle.setVehicleName(“Car”);
vehicle vehicle2 = new Vehicle();
vehicle2.setVehicleName(“Jeep”);
user.getVehicle().add(vehicle);
user.getVehicle().add(vehicle2);
vehicle.getUserList().add(user);
vehicle2.getUserList().add(user);
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
session.persists(user);
sesion.getTransation.commit();
session.close();
}
}