What is “inverse”?

This is the most confusing keyword in Hibernate, at least i took quite a long time to understand about it. The “inverse” keyword is always declared in one-to-many and many-to-many relationship (many-to-one doesn’t has inverse keyword), It defines which side is responsible to take care the relationship.

Always put inverse=”true” in your collection variable?

There are many Hibernate articles try to explain what is “inverse” with many Hibernate “official” jargon, which is very hard to understand (at least to me). In few articles, they even suggest just forget about what is “inverse”, and always put the inverse=”true” in your collection variable. I agreed this statement is always true – “inverse=true in your collection variable”, but do not blindfold on it, try to understand the reason behind is essential to optimal your Hibernate performance.

“inverse”, can it change to “relationship owner”?

In Hibernate, only the relationship owner should maintain the relationship, and the “inverse” keyword is created to defines which side is the owner to maintain the relationship. However the “inverse” keyword itself is not verbose enough, I would suggest change the keyword to “relationship_owner”. The inverse=”true” means this is the relationship owner, whereas inverse=”false” (default) means it’s not.

Let’s go though a quick example to grab an initial idea of what is “inverse” responsibility?

Preparing the data for demonstration…

1. Database tables

This is a one-to-many relationship table design, a STOCK table has many occurrences in STOCK_DAILY_RECORD table.

one-to-many-relationship

2. Hibernate implementation

Stock.java
public class Stock implements java.io.Serializable {
   ...
   private Set<StockDailyRecord> stockDailyRecords = 
                                  new HashSet<StockDailyRecord>(0);
   ...
StockDailyRecord.java
public class StockDailyRecord implements java.io.Serializable {
   ...
   private Stock stock;
   ...
Stock.hbm.xml
<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock" ...>
    ...
    <set name="stockDailyRecords" table="stock_daily_record" fetch="select">
        <key>
            <column name="STOCK_ID" not-null="true" />
        </key>
        <one-to-many class="com.mkyong.common.StockDailyRecord" />
    </set>
    ...
StockDailyRecord.hbm.xml
<hibernate-mapping>
  <class name="com.mkyong.common.StockDailyRecord" table="stock_daily_record" ...>
  ...
  <many-to-one name="stock" class="com.mkyong.common.Stock">
       <column name="STOCK_ID" not-null="true" />
  </many-to-one>
  ...

3. Question …

See this file – “Stock.hbm.xml“.

<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock" ...>
    ...
    <set name="stockDailyRecords" table="stock_daily_record" fetch="select">
        <key>
            <column name="STOCK_ID" not-null="true" />
        </key>
        <one-to-many class="com.mkyong.common.StockDailyRecord" />
    </set>
    ...

If the Set variable (stockDailyRecords) in Stock object is modified, and save the Stock object like following

Stock stock = new Stock();
stock.getStockDailyRecords().add(stockDailyRecords);
session.save(stock);

Will it update the StockDailyRecord table?

Hibernate: 
    update mkyong.stock_daily_record 
    set STOCK_ID=? 
    where DAILY_RECORD_ID=?

4. Answer …

“inverse” is controlling the above scenario, to define which side should maintain the relationship.

  • Inverse = false (default) – will execute “update mkyong.stock_daily_record” to update the relationship.
  • Inverse = true – Do nothing.

Got it? May be not, let’s explore more examples to understand about it.

“Inverse = false” example

<!--Stock.hbm.xml-->
...
<set name="stockDailyRecords" table="stock_daily_record" ...>

If no “Inverse” keyword is declared, the default is inverse = “false”, which is equal to

<!--Stock.hbm.xml-->
...
<set name="stockDailyRecords" inverse="false" table="stock_daily_record" ...>

which means both sides are the owner of the relationship. In Hibernate, it will enable two sides to update the foreign key “stock_daily_record.ITEM_ID” in “StockDailyRecord” table.

  • Stock will update the foreign key “stock_daily_record.ITEM_ID” if Set variable (stockDailyRecords) is modified.
  • StockDailyRecord will update the foreign key “stock_daily_record.ITEM_ID” with Stock property as well.

1. Insert example …

Here’s an insert example for inverse=”false”, when a Stock object is saved, Hibernate will generated two SQL statements, one insert and one update.

Stock stock = new Stock();
stock.getStockDailyRecords().add(stockDailyRecords);
session.save(stock);

Output

Hibernate: 
    insert into mkyong.stock (STOCK_CODE, STOCK_NAME) 
    values (?, ?)
...
Hibernate: 
    update mkyong.stock_daily_record 
    set STOCK_ID=? 
    where DAILY_RECORD_ID=?

Stock will update the “stock_daily_record.ITEM_ID” through Set variable (stockDailyRecords), because Stock is the relationship owner.

2. Update example …

Here’s an update example for inverse=”false”, Hibernate will generated three SQL statements, one insert and two updates.

        Query q = session.createQuery("from Stock where stockCode = :stockCode ");
        q.setParameter("stockCode", "4715");
        Stock stock = (Stock)q.list().get(0);
        stock.setStockName("GENM1");
 
        StockDailyRecord stockDailyRecords = new StockDailyRecord();
        //set stockDailyRecords data
 
        stockDailyRecords.setStock(stock);        
        stock.getStockDailyRecords().add(stockDailyRecords);
 
        session.save(stockDailyRecords);
        session.update(stock);

Output

Hibernate: 
    insert into mkyong.stock_daily_record (STOCK_ID, ...) 
    values (?, ...)
 
Hibernate: 
    update mkyong.stock 
    set STOCK_CODE=?, STOCK_NAME=? 
    where STOCK_ID=?
 
Hibernate: 
    update mkyong.stock_daily_record 
    set STOCK_ID=? 
    where DAILY_RECORD_ID=?

Stock will update the “stock_daily_record.ITEM_ID” through Set variable (stockDailyRecords), because Stock is the relationship owner.

Wait…do you think the third update statement is necessary? The inverse = “true” in Set variable (stockDailyRecords) can stop the Hibernate to generate the unnecessary third update statement.

inverse = “true” example

<!--Stock.hbm.xml-->
<set name="stockDailyRecords" inverse="true" table="stock_daily_record" ...>

The inverse=”true” is declared at the Set variable (stockDailyRecords), which means Stock is not the relationship owner, the owner is belong to StockDailyRecord class. In Hibernate, it will enable only the StockDailyRecord class to update the foreign key “stock_daily_record.ITEM_ID” in StockDailyRecord table.

  • Stock will not update the foreign key “stock_daily_record.ITEM_ID” if Set variable (stockDailyRecords) is modified.
  • Only StockDailyRecord will update the foreign key “stock_daily_record.ITEM_ID” with Stock property.

1. Insert example …

Here’s an insert example for inverse=”true”, when a Stock object is saved, Hibernate will generated one insert SQL statement.

Stock stock = new Stock();
stock.getStockDailyRecords().add(stockDailyRecords);
session.save(stock);

Output

Hibernate: 
    insert into mkyong.stock (STOCK_CODE, STOCK_NAME) 
    values (?, ?)

Since “Stock” is not the owner of the relationship, it will not update the “stock_daily_record.ITEM_ID” in StockDailyRecord table.

2. Update example …

Here’s an update example for inverse=”true”, Hibernate will generated two SQL statements, one insert and one update.

        Query q = session.createQuery("from Stock where stockCode = :stockCode ");
        q.setParameter("stockCode", "4715");
        Stock stock = (Stock)q.list().get(0);
        stock.setStockName("GENM1");
 
        StockDailyRecord stockDailyRecords = new StockDailyRecord();
        //set stockDailyRecords data
 
        stockDailyRecords.setStock(stock);        
        stock.getStockDailyRecords().add(stockDailyRecords);
 
        session.save(stockDailyRecords);
        session.update(stock);

Output

Hibernate: 
    insert into mkyong.stock_daily_record (STOCK_ID, ...) 
    values (?, ...)
 
Hibernate: 
    update mkyong.stock 
    set STOCK_CODE=?, STOCK_NAME=? 
    where STOCK_ID=?

Since “Stock” is not the owner of the relationship, it will not update the “stock_daily_record.ITEM_ID” in stockDailyRecord table.

inverse vs cascade

Both are totally different notions, see the differential here.

Conclusion

Understanding the “inverse” is essential to optimize your code, it helps to avoid many unnecessary update statements, which mention in “update example for inverse=false”. At last, try to remember the inverse=”true” mean this is the relationship owner to handle the relationship.

Reference

1. http://simoes.org/docs/hibernate-2.1/155.html
2. http://docs.jboss.org/hibernate/stable/core/reference/en/html/example-parentchild.html
3. http://tadtech.blogspot.com/2007/02/hibernate-when-is-inversetrue-and-when.html

This article was posted in Hibernate category.

Related Posts