Unidirectional and Bidirectional relationship
In order to understand this relationship take the case of Book Library.
Book Library contains collection of books. So book contains foreign key of book library
to maintain the relationship.
Book Library contains collection of books. So book contains foreign key of book library
to maintain the relationship.
From Book Library we can access books not vice versa
class Book{
Long bookId;
String bookName;
…........
}
class BookLibrary{
Long libraryId;
String libraryName;
Set<Book> bookSet;
}
Bidirectional relationship refers to the case when relationship between two objects can be accessed both ways. i.e
From Book Library we can access collection of Books and Book Object will have reference to BookLibrary
From Book Library we can access collection of Books and Book Object will have reference to BookLibrary
class Book{
Long bookId;
String bookName;
BookLibrary library;
…........
}
Though in both the cases for relationship to occur there would be foreign key mapping in Book Table corresponding to Book Library.
Cascade By Attribute
Taking the Book Library example further,lets assume we have a form/web page where we input the information regarding the library and books. So we have a library object containing library information and collection of books. In traditional JDBC approach,we will persist the Book Library first ,get the corresponding primary key and then iterate through book list and persist it one by one by adding the foreign key attribute. All this work has to be done by developer.
Similarly for updates and deletes we have to follow the same procedure.
propagated to the associated entities depending upon the value of cascade by attribute.
So taking the above example if we provide the cascade by attribute to the book set as
ALL. Whatever operations are done on BookLibrary object ,it will be passed on to the book collection object also. Developer need not have to code this,it will happen automatically.
So by providing the right cascade attributes we can govern the flow of changes from parent to child entities.
Long libraryId;
String libraryName;
…...
@Cascade(value = { CascadeType.ALL })
Set<Book> bookSet;
}
MappedBy Attribute
MappedBy Attribute is the most misunderstood concept. It comes into action when we have bi directional relationship between the entities. In relational database we have foreign key attribute which identifies the parent and child tables.
However when we have bi-directional relationship,in order to provide the identification regarding the same hibernate has come up with mappedBy attribute.
Normally mappedBy attribute is provided on the object which does not contains foreign key.
In hibernate terms,it means “I am not the owner of the relationship,ownership is governed by other entity'.
In hibernate terms,it means “I am not the owner of the relationship,ownership is governed by other entity'.
Inorder to understand it better lets take case of parent and child.Child belongs to a parent and parent can have more than one child.Its a classical case of one to many relationship.
Here mappedBy attribute is at parent side.So its the responsibilty of child to maintain the realtionship.
SQL Script
create table ORM_MappedBy_Parent( Id bigint Identity(1,1) primary key, ParentName varchar(50) not null, ParentAddr varchar(50)not null ) create table ORM_MappedBy_Child( ChildId bigint identity(1,1) primary key, ChildName varchar(50) not null, ParentId bigint null ) alter table ORM_MappedBy_Child ADD FOREIGN KEY (ParentId) REFERENCES ORM_MappedBy_Parent(Id);
Here ORM_MappedBy_Child contains the foriegn key.So Parent will have collection of child elements.
Model Classes
MappedByParent.java containing collection of Child entities with mappedBy attribute
package com.kunaal.model.mappedBy; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; import com.kunaal.model.BaseModel; /** * @author Kunaal A Trehan * */ @Entity @Table(name="ORM_MappedBy_Parent") public class MappedByParent implements BaseModel<Long>{ @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") private Long parentId; @Column(name="parentName") private String name; @Column(name="parentAddr") private String address; @OneToMany(cascade=CascadeType.ALL,mappedBy="parent") private Set<MappedByChild> childSet=new HashSet<MappedByChild>(); public Long getPrimaryKey() { return getParentId(); } /** * @return the parentId */ public Long getParentId() { return parentId; } /** * @param parentId the parentId to set */ public void setParentId(Long parentId) { this.parentId = parentId; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the address */ public String getAddress() { return address; } /** * @param address the address to set */ public void setAddress(String address) { this.address = address; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((parentId == null) ? 0 : parentId.hashCode()); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MappedByParent other = (MappedByParent) obj; if (parentId == null) { if (other.parentId != null) return false; } else if (!parentId.equals(other.parentId)) return false; return true; } /** * @return the childSet */ public Set<MappedByChild> getChildSet() { return childSet; } /** * @param childSet the childSet to set */ public void setChildSet(Set<MappedByChild> childSet) { this.childSet = childSet; } }
MappedByChild.java which is owner of the relationship
package com.kunaal.model.mappedBy; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import com.kunaal.model.BaseModel; /** * * @author Kunaal A Trehan */ @Entity @Table(name="ORM_MappedBy_Child") public class MappedByChild implements BaseModel<Long>{ @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="childId") private Long childId; @Column(name="childName") private String childName; @ManyToOne @JoinColumn(name="ParentId") private MappedByParent parent; public Long getPrimaryKey() { return getChildId(); } /** * @return the childId */ public Long getChildId() { return childId; } /** * @param childId the childId to set */ public void setChildId(Long childId) { this.childId = childId; } /** * @return the childName */ public String getChildName() { return childName; } /** * @param childName the childName to set */ public void setChildName(String childName) { this.childName = childName; } /** * @return the parent */ public MappedByParent getParent() { return parent; } /** * @param parent the parent to set */ public void setParent(MappedByParent parent) { this.parent = parent; } }
MappedDAOImpl.java which extends from BaseDAOImpl and perform basic operations like persist,update,delete,findById and others for the domain object
package com.kunaal.dao.impl; import com.kunaal.dao.IMappedDAO; import com.kunaal.model.mappedBy.MappedByParent; /** * @author Kunaal A Trehan * */ public class MappedDAOImpl extends BaseDAOImpl<MappedByParent, Long> implements IMappedDAO{ @Override public Class<MappedByParent> getEntityType() { return MappedByParent.class; } }
Abstract BaseDAOImpl.java containing all basic operations
package com.kunaal.dao.impl; import java.io.Serializable; import java.util.List; import org.hibernate.SessionFactory; import org.hibernate.classic.Session; import com.kunaal.dao.IBaseDAO; import com.kunaal.model.BaseModel; /** * @author Kunaal A Trehan * */ public abstract class BaseDAOImpl<K extends BaseModel<T>,T> implements IBaseDAO<K , T>{ private SessionFactory sessionFactory; public abstract Class<K> getEntityType(); public void persist(K object) { Session session = sessionFactory.getCurrentSession(); session.save(object); } public void update(K object) { Session session = sessionFactory.getCurrentSession(); session.update(object); } public void delete(K object) { Session session = sessionFactory.getCurrentSession(); session.delete(object); } public List<K> listAll() { Session session = sessionFactory.getCurrentSession(); return session.createCriteria(getEntityType()).list(); } public K findById(T id) { Session session = sessionFactory.getCurrentSession(); return (K) session.get(getEntityType(), (Serializable) id); } /** * @return the sessionFactory */ public SessionFactory getSessionFactory() { return sessionFactory; } /** * @param sessionFactory the sessionFactory to set */ public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } }
Abstract BaseServiceImpl.java containing all the common methods like persist,delete,update and others
package com.kunaal.service.impl; import java.util.List; import com.kunaal.dao.IBaseDAO; import com.kunaal.model.BaseModel; import com.kunaal.service.IBaseService; /** * @author Kunaal A Trehan * */ public abstract class BaseServiceImpl<K extends BaseModel<T>,T> implements IBaseService<K , T>{ private IBaseDAO<K,T> baseDAO; public void persist(K object) { getBaseDAO().persist(object); } public void update(K object) { getBaseDAO().update(object); } public void delete(K object) { getBaseDAO().delete(object); } public List<K> listAll() { return getBaseDAO().listAll(); } public K findById(T id) { return getBaseDAO().findById(id); } /** * @return the baseDAO */ public IBaseDAO<K, T> getBaseDAO() { return baseDAO; } /** * @param baseDAO the baseDAO to set */ public void setBaseDAO(IBaseDAO<K, T> baseDAO) { this.baseDAO = baseDAO; } }
MappedServiceImpl .java extending from BaseServiceImpl
package com.kunaal.service.impl; import com.kunaal.model.mappedBy.MappedByParent; import com.kunaal.service.IMappedService; /** * @author Kunaal A Trehan * */ public class MappedServiceImpl extends BaseServiceImpl<MappedByParent, Long> implements IMappedService{ }
MappedServiceTest.java
In this test class we have two methods
-insertProperInfo
-insertImProperInfo
In insertProperInfo() ,child entity is attaching itself to parent and thus forming the relationship.
In insertImProperInfo(),child entity is not associating itself to parent.So no relationship is formed.As a result of which foreign key is passed as NULL in the database.
package com.kunaal.service; import java.util.HashSet; import java.util.Set; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.transaction.TransactionConfiguration; import org.springframework.transaction.annotation.Transactional; import com.kunaal.model.mappedBy.MappedByChild; import com.kunaal.model.mappedBy.MappedByParent; /** * @author Kunaal A Trehan * */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:spring-main.xml"}) @TransactionConfiguration(defaultRollback=false) public class MappedServiceTest implements ApplicationContextAware{ private ApplicationContext appCtx; @Autowired private IMappedService mappedService; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.appCtx=applicationContext; } /** * In this test case all information and relationships are made proper */ @Test @Transactional public void insertProperInfo(){ MappedByParent parent=new MappedByParent(); MappedByChild child1=new MappedByChild(); MappedByChild child2=new MappedByChild(); parent.setAddress("Bangalore"); parent.setName("Parent1"); child1.setChildName("Child1"); child2.setChildName("child2"); //make associations child1.setParent(parent); child2.setParent(parent); Set<MappedByChild> childSet=new HashSet<MappedByChild>(); childSet.add(child1); childSet.add(child2); parent.setChildSet(childSet); mappedService.persist(parent); } @Test @Transactional public void insertImProperInfo(){ MappedByParent parent=new MappedByParent(); MappedByChild child1=new MappedByChild(); MappedByChild child2=new MappedByChild(); parent.setAddress("Bangalore"); parent.setName("Parent2"); child1.setChildName("ImproperChild1"); child2.setChildName("ImproperChild2"); //make associations //HERE I AM NOT PUTTING THE RELATIONSHIP ASSOCIATION SO //RELATIONSHIPS ARE NOT SET.THERE WILL BE NULL IN THE FOREIGN KEY [ParentId] //child1.setParent(parent); //child2.setParent(parent); Set<MappedByChild> childSet=new HashSet<MappedByChild>(); childSet.add(child1); childSet.add(child2); parent.setChildSet(childSet); mappedService.persist(parent); } }
SQL Server screen showing the information after the test case execution.
@OneToMany(cascade=CascadeType.ALL,mappedBy="parent")
ReplyDeleteWhat does "parent" reference? Its not the name of the parent table, and its not the name of the parent class... where is this defined?
Thanks!
'parent' refers to field
Deleteprivate MappedByParent parent; in MappedByChild class
@OneToMany(cascade=CascadeType.ALL,mappedBy="parent") means that there is one to many relationship between me and child entity.However
onus of maintaining the relationship is on the child side.
Hope it helps
nice expaination
ReplyDeleteThanks a lot! You made a new blog entry to answer my question; I really appreciate your time and effort.
ReplyDeletebest java training in chennai |
java training center in chennai