Bidirectional associations by R4R Team

In hibernate a bidirectional association allows to navigation from both "ends" of the association. Here we knows about the two kind of bidirectional association which support those are below:

1. One to Many: Here in we do set or bag valued at one end, single-valued at the other.

2. Many to Many: Here we set of bag valued at both ends.

Here many to one association does exists which is the owner side of a bidirectional relationship. When ever for this corrosponding one to many association is in this case annotated by @OneToMany(mappedBy=..)

We can take a small example to understand for this conversation of Bidirectional one to many with many to one side as associate owner:

@Entity
public class Roop {
    @OneToMany(mappedBy="Roop")
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk")
    public Troop getTroop() {
    ...
}

Roop has a bidirectional one to many relationship with Soldier through the Roop property. So we don't have to define the physical mapping in the mappedBy side.

When we want to bidirectional one to many relationship, with the one-to-many side as the owning side, so have to remove the mappedBy element and set the many to one @JoinColumn as insertable and updatable to false. This solution is not optimized and will produce additional UPDATE statements.

So specify a bidirectional many to many association simply by mapping to many to many association to the same database table and declaring one end as inverse. (Which can be choice but can't be an indexed collection).

Example of Bidirectional associtaion with one to many side as owner

@Entity
public class Troop {
    @OneToMany
    @JoinColumn(name="troop_fk") //we need to duplicate the physical information
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk", insertable=false, updatable=false)
    public Troop getTroop() {
    ...
}

We need to know that how does the mapping of a bidirectional mapping look like in hibernate mapping in xml? There we need to define the bidirectional one-to-many association by mapping a one to many association to the same table colum as a many to one association and declaring the many valued and inverse="true"

Example of Bidirectional one to many via Hibernate mapping files


<class name="Parent">
    <id name="id" column="parent_id"/>
    ....
    <set name="children" inverse="true">
        <key column="parent_id"/>
        <one-to-many class="Child"/>
    </set>
</class>

<class name="Child">
    <id name="id" column="child_id"/>
    ....
    <many-to-one name="parent" 
        class="Parent" 
        column="parent_id"
        not-null="true"/>
</class>

We have to know that mapping one end to an association with inverse="true" does not affect the operation of cascades as these are orthogonal concepts.

We can define a many to many association logically used the @ManyToMany annotation. So here also we have to describe the association table and the join conditions using the @JoinTable annotation. If the assocation tis bidirectional, One side has to be the owner and one side thas to be the inverse end. But it will be ignored when updating the relationship values in the association table.

Example of the Many to many association via @ManyToMany:

@Entity
public class Student implements Serializable {
    @ManyToMany(
        targetEntity=org.hibernate.test.metadata.manytomany.Student.class,
        cascade={CascadeType.PERSIST, CascadeType.MERGE}
    )
    @JoinTable(
        name="STUDENT_STUDENT",
        joinColumns=@JoinColumn(name="SUTD_ID"),
        inverseJoinColumns=@JoinColumn(name="SUTD_ID")
    )
    public Collection getStudent() {
        return student;
    }
    ...
}              
@Entity
public class Student implements Serializable {
    @ManyToMany(
        cascade = {CascadeType.PERSIST, CascadeType.MERGE},
        mappedBy = "employees",
        targetEntity = Student.class
    )
    public Collection getStudnets() {
        return students;
    }
}         

We can see in this example @JoinTable defines a name an array of join columns and an array of inverse join columns.Which letter ones are in the columns of the association table which refer to the Student primary key. As see in the last other side don't have to describe the physical mapping a simple mappedBy argument containing the owner side property name bind the two.

We can see in any another annotation we gussed most values in a many to many relationship. we can make the physical mapping without describing in a undirectional many to many association so there can not applied the rule of mapping. The table name is the concatentaition of the owner table name _ and the other side table name. That table name the refrencing the owner table is the cocatenation of the owner table name, _ and the owner primary key column.

Example of Default values for @ManyToMany (uni-directional)

@Entity
public class Store_Student {
    @ManyToMany(cascade = CascadeType.PERSIST)
    public Set<City> getImplantedIn() {
        ...
    }
}

@Entity
public class City_Student {
    ... //no bidirectional relationship
}             

In the above example of the association a Store_Student is used as the join table. The store_id columns is a foregin key to the sotre table. The implantedIn_id column is a foregin key to the City_Student table.

Without describing the mapping with the physical mapping in ab bidirectional many to many the following rules applied. The table name is the concatention of the owner table name, _ and the other side table name. The foreign key name  referencing the owner table is the concatentation of the othe side property name, _ , and the owner primary key column.

Example of the Default values for @ManyToMany (bi-directional):

@Entity
public class Store_Student {
    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    public Set<Customer> getCustomer_Student() {
        ...
    }
}

@Entity
public class Customer_Student {
    @ManyToMany(mappedBy="customers")
    public Set<Store> getStores_Student() {
        ...
    }
}         

A Store_City is used as the join table. The Store_id column is a foreign key to the Store table. The implantedIn_id column is a foreign key to the City table.

Without describing any physical mapping in a bidirectional many to many the following rules applied. The table name is the concatenation of the owner table name, _ and the other side table name. The foreign key name(s) referencing the owner table is the concatenation of the other side property name, _, and the owner primary key column(s). The foreign key name(s) referencing the other side is the concatenation of the owner property name, _, and the other side primary key column(s). These are the same rules used for a unidirectional one to many relationship.

Example of the Default values for @ManyToMany (bi-directional):

@Entity
public class Store_Student {
    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    public Set<Customer> getCustomers_Studnet() {
        ...
    }
}

@Entity
public class Customer_Student {
    @ManyToMany(mappedBy="customers")
    public Set<Store> getStores_Studnety() {
        ...
    }
}        

A Store_Customer is used as the join table. The stores_id column is a foreign key to the Store table. The customers_id column is a foreign key to the Customer table.

Using Hibernate mapping files you can map a bidirectional many-to-many association by mapping two many-to-many associations to the same database table and declaring one end as inverse.

Important point: cannot select an indexed collection.

To understand this we take a small example of a bidirectional many-to-many association, In the database each category have many items and each item can be in many category:

<class name="Category">
    <id name="id" column="CATEGORY_ID"/>
    ...
    <bag name="items" table="CATEGORY_ITEM">
        <key column="CATEGORY_ID"/>
        <many-to-many class="Item" column="ITEM_ID"/>
    </bag>
</class>

<class name="Item">
    <id name="id" column="ITEM_ID"/>
    ...

    <!-- inverse end -->
    <bag name="categories" table="CATEGORY_ITEM" inverse="true">
        <key column="ITEM_ID"/>
        <many-to-many class="Category" column="CATEGORY_ID"/>
    </bag>
</class>

Here in the given example Changes made only to the inverse end of the association which are not persisted. It mean Hibernate has two representations in memory for every bidirectional association, one link from A to B and another link from B to A. we can understand to this very easily the Java object model and how we create a many-to-many relationship in Java:

category.getItems().add(item);          
item.getCategories().add(category);     
session.persist(item);                   // The relationship won't be saved!
session.persist(category);               // The relationship will be saved
Leave a Comment:
Search
Categories
R4R Team
R4Rin Top Tutorials are Core Java,Hibernate ,Spring,Sturts.The content on R4R.in website is done by expert team not only with the help of books but along with the strong professional knowledge in all context like coding,designing, marketing,etc!