Hibernate – Many-to-Many example – join table + extra column (Annotation)

In this tutorial, we show you how to use Hibernate to implements “many-to-many table relationship, with extra column in the join table“.

Note
For many to many relationship with NO extra column in the join table, please refer to this @many-to-many tutorial

1. Many-to-many table + extra columns in join table

The STOCK and CATEGORY many to many relationship is linked with a third / join table named STOCK_CATEGORY, with extra “created_by” and “created_date” columns.

many to many diagram

MySQL table script


CREATE TABLE `stock` (
  `STOCK_ID` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `STOCK_CODE` VARCHAR(10) NOT NULL,
  `STOCK_NAME` VARCHAR(20) NOT NULL,
  PRIMARY KEY (`STOCK_ID`) USING BTREE,
  UNIQUE KEY `UNI_STOCK_NAME` (`STOCK_NAME`),
  UNIQUE KEY `UNI_STOCK_ID` (`STOCK_CODE`) USING BTREE
)
 
CREATE TABLE `category` (
  `CATEGORY_ID` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `NAME` VARCHAR(10) NOT NULL,
  `DESC` VARCHAR(255) NOT NULL,
  PRIMARY KEY (`CATEGORY_ID`) USING BTREE
)

CREATE TABLE  `stock_category` (
  `STOCK_ID` INT(10) UNSIGNED NOT NULL,
  `CATEGORY_ID` INT(10) UNSIGNED NOT NULL,
  `CREATED_DATE` DATE NOT NULL,
  `CREATED_BY` VARCHAR(10) NOT NULL,
  PRIMARY KEY (`STOCK_ID`,`CATEGORY_ID`),
  CONSTRAINT `FK_CATEGORY_ID` FOREIGN KEY (`CATEGORY_ID`) 
             REFERENCES `category` (`CATEGORY_ID`),
  CONSTRAINT `FK_STOCK_ID` FOREIGN KEY (`STOCK_ID`) 
             REFERENCES `stock` (`STOCK_ID`)
)

2. Project Structure

Review the file project structure of this tutorial.

many to many project folder

3. Hibernate / JPA Annotation

The Hibernate / JBoss tools generated annotation codes are not working in this third table extra column scenario. To make it works, you should customize the code to use “@AssociationOverride“, in StockCategory.java to represent the many to many relationship.

See following customized codes :

File : Stock.java


package com.mkyong.stock;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name = "stock", catalog = "mkyongdb", uniqueConstraints = {
		@UniqueConstraint(columnNames = "STOCK_NAME"),
		@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {

	private Integer stockId;
	private String stockCode;
	private String stockName;
	private Set<StockCategory> stockCategories = new HashSet<StockCategory>(0);

	public Stock() {
	}

	public Stock(String stockCode, String stockName) {
		this.stockCode = stockCode;
		this.stockName = stockName;
	}

	public Stock(String stockCode, String stockName,
			Set<StockCategory> stockCategories) {
		this.stockCode = stockCode;
		this.stockName = stockName;
		this.stockCategories = stockCategories;
	}

	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "STOCK_ID", unique = true, nullable = false)
	public Integer getStockId() {
		return this.stockId;
	}

	public void setStockId(Integer stockId) {
		this.stockId = stockId;
	}

	@Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
	public String getStockCode() {
		return this.stockCode;
	}

	public void setStockCode(String stockCode) {
		this.stockCode = stockCode;
	}

	@Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
	public String getStockName() {
		return this.stockName;
	}

	public void setStockName(String stockName) {
		this.stockName = stockName;
	}

	@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.stock", cascade=CascadeType.ALL)
	public Set<StockCategory> getStockCategories() {
		return this.stockCategories;
	}

	public void setStockCategories(Set<StockCategory> stockCategories) {
		this.stockCategories = stockCategories;
	}

}

File : StockCategory.java


package com.mkyong.stock;

import java.util.Date;

import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

@Entity
@Table(name = "stock_category", catalog = "mkyongdb")
@AssociationOverrides({
		@AssociationOverride(name = "pk.stock", 
			joinColumns = @JoinColumn(name = "STOCK_ID")),
		@AssociationOverride(name = "pk.category", 
			joinColumns = @JoinColumn(name = "CATEGORY_ID")) })
public class StockCategory implements java.io.Serializable {

	private StockCategoryId pk = new StockCategoryId();
	private Date createdDate;
	private String createdBy;

	public StockCategory() {
	}

	@EmbeddedId
	public StockCategoryId getPk() {
		return pk;
	}

	public void setPk(StockCategoryId pk) {
		this.pk = pk;
	}

	@Transient
	public Stock getStock() {
		return getPk().getStock();
	}

	public void setStock(Stock stock) {
		getPk().setStock(stock);
	}

	@Transient
	public Category getCategory() {
		return getPk().getCategory();
	}

	public void setCategory(Category category) {
		getPk().setCategory(category);
	}

	@Temporal(TemporalType.DATE)
	@Column(name = "CREATED_DATE", nullable = false, length = 10)
	public Date getCreatedDate() {
		return this.createdDate;
	}

	public void setCreatedDate(Date createdDate) {
		this.createdDate = createdDate;
	}

	@Column(name = "CREATED_BY", nullable = false, length = 10)
	public String getCreatedBy() {
		return this.createdBy;
	}

	public void setCreatedBy(String createdBy) {
		this.createdBy = createdBy;
	}

	public boolean equals(Object o) {
		if (this == o)
			return true;
		if (o == null || getClass() != o.getClass())
			return false;

		StockCategory that = (StockCategory) o;

		if (getPk() != null ? !getPk().equals(that.getPk())
				: that.getPk() != null)
			return false;

		return true;
	}

	public int hashCode() {
		return (getPk() != null ? getPk().hashCode() : 0);
	}
}

File : StockCategoryId.java


package com.mkyong.stock;

import javax.persistence.Embeddable;
import javax.persistence.ManyToOne;

@Embeddable
public class StockCategoryId implements java.io.Serializable {

	private Stock stock;
    private Category category;

	@ManyToOne
	public Stock getStock() {
		return stock;
	}

	public void setStock(Stock stock) {
		this.stock = stock;
	}

	@ManyToOne
	public Category getCategory() {
		return category;
	}

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

	public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        StockCategoryId that = (StockCategoryId) o;

        if (stock != null ? !stock.equals(that.stock) : that.stock != null) return false;
        if (category != null ? !category.equals(that.category) : that.category != null)
            return false;

        return true;
    }

    public int hashCode() {
        int result;
        result = (stock != null ? stock.hashCode() : 0);
        result = 31 * result + (category != null ? category.hashCode() : 0);
        return result;
    }
    
}

File : Category.java


package com.mkyong.stock;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "category", catalog = "mkyongdb")
public class Category implements java.io.Serializable {

	private Integer categoryId;
	private String name;
	private String desc;
	private Set<StockCategory> stockCategories = new HashSet<StockCategory>(0);

	public Category() {
	}

	public Category(String name, String desc) {
		this.name = name;
		this.desc = desc;
	}

	public Category(String name, String desc, Set<StockCategory> stockCategories) {
		this.name = name;
		this.desc = desc;
		this.stockCategories = stockCategories;
	}

	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "CATEGORY_ID", unique = true, nullable = false)
	public Integer getCategoryId() {
		return this.categoryId;
	}

	public void setCategoryId(Integer categoryId) {
		this.categoryId = categoryId;
	}

	@Column(name = "NAME", nullable = false, length = 10)
	public String getName() {
		return this.name;
	}

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

	@Column(name = "[DESC]", nullable = false)
	public String getDesc() {
		return this.desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.category")
	public Set<StockCategory> getStockCategories() {
		return this.stockCategories;
	}

	public void setStockCategories(Set<StockCategory> stockCategories) {
		this.stockCategories = stockCategories;
	}

}

Done, the many to many relationship should be working now.

4. Run it – Case 1

For a new category and a new stock.


    session.beginTransaction();

    Stock stock = new Stock();
    stock.setStockCode("7052");
    stock.setStockName("PADINI");
 
    Category category1 = new Category("CONSUMER", "CONSUMER COMPANY");
    //new category, need save to get the id first
    session.save(category1);
    
    StockCategory stockCategory = new StockCategory();
    stockCategory.setStock(stock);
    stockCategory.setCategory(category1);
    stockCategory.setCreatedDate(new Date()); //extra column
    stockCategory.setCreatedBy("system"); //extra column
        
    stock.getStockCategories().add(stockCategory);
        
    session.save(stock);
       
    session.getTransaction().commit();

Output…


Hibernate: 
    insert 
    into
        mkyongdb.category
        (`DESC`, NAME) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    values
        (?, ?)
Hibernate: 
    select
        stockcateg_.CATEGORY_ID,
        stockcateg_.STOCK_ID,
        stockcateg_.CREATED_BY as CREATED1_2_,
        stockcateg_.CREATED_DATE as CREATED2_2_ 
    from
        mkyongdb.stock_category stockcateg_ 
    where
        stockcateg_.CATEGORY_ID=? 
        and stockcateg_.STOCK_ID=?
Hibernate: 
    insert 
    into
        mkyongdb.stock_category
        (CREATED_BY, CREATED_DATE, CATEGORY_ID, STOCK_ID) 
    values
        (?, ?, ?, ?)

5. Run it – Case 2

Get an existing category and a new stock.


   session.beginTransaction();

    Stock stock = new Stock();
    stock.setStockCode("7052");
    stock.setStockName("PADINI");
 
    //assume category id is 7
    Category category1 = (Category)session.get(Category.class, 7);
    
    StockCategory stockCategory = new StockCategory();
    stockCategory.setStock(stock);
    stockCategory.setCategory(category1);
    stockCategory.setCreatedDate(new Date()); //extra column
    stockCategory.setCreatedBy("system"); //extra column
        
    stock.getStockCategories().add(stockCategory);
        
    session.save(stock);
       
    session.getTransaction().commit();

Output…


Hibernate: 
    select
        category0_.CATEGORY_ID as CATEGORY1_1_0_,
        category0_.`DESC` as DESC2_1_0_,
        category0_.NAME as NAME1_0_ 
    from
        mkyongdb.category category0_ 
    where
        category0_.CATEGORY_ID=?
Hibernate: 
    insert 
    into
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    values
        (?, ?)
Hibernate: 
    select
        stockcateg_.CATEGORY_ID,
        stockcateg_.STOCK_ID,
        stockcateg_.CREATED_BY as CREATED1_2_,
        stockcateg_.CREATED_DATE as CREATED2_2_ 
    from
        mkyongdb.stock_category stockcateg_ 
    where
        stockcateg_.CATEGORY_ID=? 
        and stockcateg_.STOCK_ID=?
Hibernate: 
    insert 
    into
        mkyongdb.stock_category
        (CREATED_BY, CREATED_DATE, CATEGORY_ID, STOCK_ID) 
    values
        (?, ?, ?, ?)

Done.

Reference

  1. Hibernate Mapping Documentation

146 comments on “Hibernate – Many-to-Many example – join table + extra column (Annotation)

  1. Hello Sir,

    When i am trying to execute <stock.getStockCategories()> statement then i am getting following error:

    ClassName=o.h.e.loading.internal.LoadContexts Message=HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@6c1548c0<rs=HikariProxyResultSet@1324915780 wrapping oracle.jdbc.driver.ForwardOnlyResultSet@7ab2d65e>

    can you please help me here please

  2. Getting following error
    Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: NULL not allowed for column “STOCK_ID”; SQL statement:

  3. Hi, thanks for your example. I have a problem I want to add unique constraint on table stockCategory on two fields ” pk.stock and pk.category” when I create this IN StockCategory table I give this error:
    Unable to create unique key constraint (STOCK_ID, CATEGORY_ID) on table StockCategory : database column ‘STOCK_ID’, ‘CATEGORY_ID’ not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational type

  4. Hi,
    Nice explanation, good article.
    However, when I am saving the parent entity it is throwing
    org.springframework.dao.DataIntegrityViolationException: A different object with the same identifier value was already associated with the session.

    My use case is pretty much same,
    Category table already has records and trying to update the references from Stock and Category Set with references to create mapping.
    Problems faced:-
    1. That above exception.
    2. orphanRemoval=true is also not working.
    3. update and delete to the stock_category doesn’t work

    Anybody who faced the same problem as mine? Please help me out.

  5. Hi I am getting below compile time error.

    Persistent type of override attribute “pk.stock” cannot be resolved
    Persistent type of override attribute “pk.catagory” cannot be resolved

    I am using JPA,jdk7,eclipse mars2…. Please help me out.

  6. isn’t the job of jpa/hibernate is to make us focus on object oriented programming rather than thinking in solving relational model problem? because this solution is relational model oriented.

  7. mkyong, thank you for this tutorial. Can you tell me if there is a way to use hibernate ‘criteria’ to query with conditions on the ‘middle’ table. So for example I want to get the stock for a particular category that has been created by a certain person?

  8. Awesome tutorial! Unfortunately, I’m having trouble updating and/or deleting entries. Can someone please provide some examples of how to delete and update?

  9. Everything works until i add @Audited annotation. Seems that Envers can’t process “mapped by” attribute.
    Caused by: org.hibernate.MappingException: Unable to read the mapped by attribute for stockCategories in com.mkyong.stock.StockCategory!

    I’m using Hibernate and Envers 4.3.7.Final.

  10. What is the reason why you did not use two many-to-one’s in the junction class? So you neither have to touch Student nor Class

  11. If I try to convert the objects to json using Jackson, I either get org.codehaus.jackson.map.JsonMappingException: failed to lazily initialize a collection of role: com.mkyong.stock.Stock.stockCategories or if I fetch EAGER, I get infinite recursion exception. Do you know a solution to this? I tried @JsonIgnore, @JsonManagedReference, and @JsonIdentityInfo but none work.

    1. In this situations, you need to avoid using bidirectional relation – that is what is creating infinite recursion.
      For example : Instead of

      @OneToMany(mappedBy=”property_in_other_Entity”)
      private Set columns;

      …you could use

      @javax.persistence.Transient
      private Set columns;

  12. Good tutorial.
    I have a prblem when I try to save more records . I get the following error:

    org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session :

    This is my code:

    public void addContacto(Proyecto proyecto, Contacto contacto, String tipo) {
    Session session = sessionFactory.openSession();
    Transaction tx = null;
    try{
    tx = session.beginTransaction();
    ContactoProyecto contactoProyecto = new ContactoProyecto();
    Proyecto p = (Proyecto)session.get(Proyecto.class, proyecto.getId());
    Contacto c = (Contacto)session.get(Contacto.class, contacto.getId());
    contactoProyecto.setContacto(c);
    contactoProyecto.setProyecto(p);
    contactoProyecto.setTipo(tipo);
    p.getContactoProyectos().add(contactoProyecto);
    session.saveOrUpdate(p);
    tx.commit();
    }catch (HibernateException e) {
    if (tx!=null) tx.rollback();
    e.printStackTrace();
    }finally {
    session.close();

    }
    }

  13. Good Tutorial.
    I have a problem when recording multiple records.
    I get the error

    org.hibernate.NonUniqueObjectException:

    My code of transaction is:

    Session session = sessionFactory.openSession();
    Transaction tx = null;
    try{
    tx = session.beginTransaction();
    ContactoProyecto contactoProyecto = new ContactoProyecto();
    Proyecto p = (Proyecto)session.get(Proyecto.class, proyecto.getId());
    Contacto c = (Contacto)session.get(Contacto.class, contacto.getId());
    contactoProyecto.setContacto(c);
    contactoProyecto.setProyecto(p);
    contactoProyecto.setTipo(tipo);
    p.getContactoProyectos().add(contactoProyecto);
    session.saveOrUpdate(p);
    tx.commit();
    }catch (HibernateException e) {
    if (tx!=null) tx.rollback();
    e.printStackTrace();
    }finally {
    session.close();

    }

  14. Great tutorial!!!

    I’m having difficulty getting this approach (or the one that used @IdClass) working when the entities are audited with Envers. Any thoughts?

  15. Is it possible to get all StockCategory objects for Category of consumer (new Category(“CONSUMER”, “CONSUMER COMPANY”)) using Criteria API .

  16. It works. But when I try to create another association, table stock_market for example, when I already has the table stock_category the hibernate blows up and give lots of errors and doesn’t give any clues to solve the problem.
    The Hibernate create the tables but don’t allow me to add data in the table stock_market.

  17. Is there any way I can have an explicit id field for stock_category table. Now the primary key is combination of stockid and categoryid.. So I am not able to put a new row with same stock and category but different date

  18. i dont think people should be using a third class for this. there should be a stock and a category class and one or both can have the extra properties as well as a list of the other class

  19. XML mapping would be good here too.
    I have a similar setup but see issues when fetching the join table with the two foreign keys.

    I have a user table, group table, and a userGroup table with an extra field type.

    When fetching the Set of userGroup in group table, I can get the actual group but only the user id and not the content.

    When fetching the Set of userGroup in user table, I can get the actual user but only the group id and not the content.

    Is anyone having this issue? Ideal is that when fetching the set of userGroup from the group I will be able to get the group object and the user object. Am I missing something in the xml mapping that enables that?

  20. Following the tutorial, I have created two
    entities corresponding to my normal tables, and another for my association table with an embedded id.

    To guarantee unicity, I have overridden methods equals and hashCode and the collections are of type Set.

    When i persist i’m only getting a null error (see the whole error below), so this gives me no clue about what i’m doing wrong.

    Following are the relations of the entities, how they are set and the error.

    Entity 1 Prestation :

    @OneToMany(fetch=FetchType.LAZY, mappedBy=”id.prestation”, cascade={CascadeType.MERGE, CascadeType.PERSIST})
    private Set louers = new HashSet(0);

    Entity 2 Materiel :

    @OneToMany(fetch=FetchType.LAZY, mappedBy=”id.materiel”)
    private Set louers = new HashSet(0);

    Entity 3 Louer :

    @AssociationOverrides
    (
    {
    @AssociationOverride(name=”id.materiel”, joinColumns = @JoinColumn(name = “ID_MAT”)),
    @AssociationOverride(name=”id.prestation”, joinColumns = @JoinColumn(name=”ID_PREST”))
    }
    )

    @Transient
    private Materiel materiel;

    @Transient
    private Prestation prestation;

    Embeddable class LouerPK :

    @ManyToOne
    private Materiel materiel;

    @ManyToOne
    private Prestation prestation;

    Setting :

    louer.setMateriel(mat);
    louer.setPrestation(prest);
    prest.getLouers().add(louer);

    Error :

    ERROR [model.exception.DAOException] (default task-50) null

    Can anyone help?

  21. How can I do the update on the join table? For example if I have 2 relations for stock but with an update I create 3 relations?

  22. the tutorial is very good. Btw me too i need to know how to do the Stock update, updating also the Set StockCategory. I really can’t understand how is it so hard with hibernate / spring mvc doing simple things such this. I think is much much easier use queries like long time ago…

  23. where can i find an example / tutorial for a form with checboxes of a many-to-many relationship?

    because i always get “No converter found capable of converting from type java.lang.String to type @javax.persistence.OneToMany java.util.Set”

  24. Hi I have one issue with your example in case of update all things are working good but the
    orphan object is not deleted after putting orphan=”true”, also hibernate is not running the
    delete query.

    Any suggestion how the hibernate will delete the orphan object while updating will be really helpful …

    thanks

    1. I used “orphanRemoval=true” from javax.persistence.OneToMany. It works.

      @OneToMany(fetch = FetchType.LAZY, mappedBy = “pk.category”, cascade=CascadeType.ALL, orphanRemoval=true)

  25. Thanks for your tutorial! I have a question, How can I do to make an inquiry? I have “stock” and the name “category”. Consultation is with Criteria and meta-models. Help me please!

  26. Dear Mkyong,

    thank you for your great article. Depend on your source programs I tried your case 1. I use Netbeans 7.4, MySql 5.6.15, Hibernate 3.6.10.Final. MySQL dont like DESC field, I changed it to DESCRIPTION.
    I dont know, what I made wrong, but in case 1 the session.save(stock) not saved data in the middle (stock_category) table. I have no error.

    12:28:07,688 INFO [stdout] (http-/127.0.0.1:8080-2) Hibernate:
    12:26:51,525 INFO [stdout] (http-/127.0.0.1:8080-2) insert
    12:26:51,525 INFO [stdout] (http-/127.0.0.1:8080-2) into
    12:26:51,526 INFO [stdout] (http-/127.0.0.1:8080-2) mydb.category
    12:26:51,527 INFO [stdout] (http-/127.0.0.1:8080-2) (DESCRIPTION, NAME)
    12:26:51,527 INFO [stdout] (http-/127.0.0.1:8080-2) values
    12:26:51,528 INFO [stdout] (http-/127.0.0.1:8080-2) (?, ?)

    12:28:07,688 INFO [stdout] (http-/127.0.0.1:8080-2) Hibernate:
    12:28:07,689 INFO [stdout] (http-/127.0.0.1:8080-2) insert
    12:28:07,690 INFO [stdout] (http-/127.0.0.1:8080-2) into
    12:28:07,691 INFO [stdout] (http-/127.0.0.1:8080-2) mydb.stock
    12:28:07,692 INFO [stdout] (http-/127.0.0.1:8080-2) (STOCK_CODE, STOCK_NAME)
    12:28:07,693 INFO [stdout] (http-/127.0.0.1:8080-2) values
    12:28:07,694 INFO [stdout] (http-/127.0.0.1:8080-2) (?, ?)

    In the Stock and Category tables have rows.

    Dou you have any idea?
    Thank you

  27. Hello!

    Tell me , please.

    Why do we need to write “stock.getStockCategories().add(stockCategory);”

    in 4. Run it – Case 1? Is it possible just to save stockCategory persistance first, and then stock persistance manually?

  28. Hi,

    Sir i like your effort for Doing so many things for us(Developer) and i like your Blog also.But i have one Question Regarding One Example in Hibernate so please help me to Describe that.

    My question is that in hibernate https://mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/ on this page class Name like : StockCategoryId.java I want to know its hashCode() method has one line which multiply variable result with 31 something like below.

    result = 31 * result + (category != null ? category.hashCode() : 0);

    My Questions are below

    1>I want to know that it does any number i can multiply to result.

    2>why u multipy to result with 31.

    3>why this method(hashCode()) is necessary.

    Eagerly waititng for your replay on this.Thanks in Advance.

    Thanks

    1. A hashcode must be a unique identifier for all values inside the object -> if one value changes, the hashcode must change.
      If you only add up to numbers, there are multiple cases where different values lead to the same number. For example 6 + 2 = 8, 5 + 3 = 8
      If you take a primenumber (31 for example) and mulitply one of the values with it and then add up the second value, there will never be the same output for different values.
      6 * 31 + 2 = 188
      5 * 31 + 3 = 158

      You need to mulitply the hashcode of one object by a primnumber and then add up the second hashcode in order to generate a new unique hashcode that represents the combination of these 2 objects.

  29. Good afternoon Mkyong and coleagues,

    I have problems when the extra column is another joinable column, which references to another table.

    For instance, in your example in stock_category there is another field which references to stock again

    private Stock relatedStock;

    @ManyToOne
    @JoinColumn(name = “related_stock_id” ,nullable=true)
    public Stock getRelatedStock() {
    return relatedStock;
    }

    public void setRelatedStock(Stock relatedStock) {
    this.relatedStock = relatedStock;
    }

    Then, doing a simple main it returns an:

    Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column relatedStock

    Thank you!

  30. Whatever I try I get the following exception:

    org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property […]
    at org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:101)
    at org.hibernate.mapping.Component$ValueGenerationPlan.execute(Component.java:422)
    at org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate(CompositeNestedGeneratedValueGenerator.java:121)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:117)
    at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:843)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:836)
    at org.hibernate.ejb.engine.spi.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:53)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:388)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:331)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:209)
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:418)
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:358)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:334)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:209)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:166)

    I’m using a DB2 (AS/400) database.

    1. “The value 31 was chosen because it is an odd prime. If it were even and the multiplication overflowed, information would be lost, as multiplication by 2 is equivalent to shifting” Read Effective Java, Second Ed. Chapter 3, Item 9.

  31. I have a question :

    is there any benefit to declare :
    private Set stockCategories
    in both classes Stock and Category ?

    I think that it will slow down the loading in java bean entities, especially when we have a lot of items in both tables stock and category in database.

    thank you.

  32. Hi sir,
    My name is siddhant.
    I have implemented ur example. But at the time of saving it is throwing an error
    Exception in thread “main” java.lang.NullPointerException

    /**
    package SampleJavaProject.Entity;

    import java.io.Serializable;

    /**
    * @author Siddhant_S
    *
    */
    @Entity
    @Table(name = “person”, schema = “test”)
    public class Person implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;
    @Column(precision = 2)
    private double amount;
    private Calendar birthDate;
    private String street;
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = “pk.person”)
    private Set bank;

    /**
    *
    */
    public Person() {
    }

    /**
    * @param name
    * @param amount
    * @param birthDate
    * @param street
    * @param bank
    */
    public Person(String name, double amount, Calendar birthDate, String street) {
    this.name = name;
    this.amount = amount;
    this.birthDate = birthDate;
    this.street = street;
    this.bank = bank;
    }

    /**
    * @return the id
    */
    public int getId() {
    return id;
    }

    /**
    * @param id
    * the id to set
    */
    public void setId(int id) {
    this.id = id;
    }

    /**
    * @return the name
    */
    public String getName() {
    return name;
    }

    /**
    * @param name
    * the name to set
    */
    public void setName(String name) {
    this.name = name;
    }

    /**
    * @return the amount
    */
    public double getAmount() {
    return amount;
    }

    /**
    * @param amount
    * the amount to set
    */
    public void setAmount(double amount) {
    this.amount = amount;
    }

    /**
    * @return the birthDate
    */
    public Calendar getBirthDate() {
    return birthDate;
    }

    /**
    * @param birthDate
    * the birthDate to set
    */
    public void setBirthDate(Calendar birthDate) {
    this.birthDate = birthDate;
    }

    /**
    * @return the street
    */
    public String getStreet() {
    return street;
    }

    /**
    * @param street
    * the street to set
    */
    public void setStreet(String street) {
    this.street = street;
    }

    /**
    * @return the bank
    */
    public Set getBank() {
    return bank;
    }

    /**
    * @param bank
    * the bank to set
    */
    public void setBank(Set bank) {
    this.bank = bank;
    }
    }

    /**
    package SampleJavaProject.Entity;

    import java.io.Serializable;

    /**
    * @author Siddhant_S
    *
    */
    @Entity
    @Table(name = “Bank”, schema = “test”)
    public class Bank implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;
    @Column(precision = 2)
    private double amount;
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = “pk.bank”)
    private Set associations;

    /**
    *
    */
    public Bank() {
    }

    /**
    * @param name
    * @param amount
    * @param associations
    */
    public Bank(String name, double amount) {
    this.name = name;
    this.amount = amount;
    }

    /**
    * @return the id
    */
    public int getId() {
    return id;
    }

    /**
    * @param id
    * the id to set
    */
    public void setId(int id) {
    this.id = id;
    }

    /**
    * @return the name
    */
    public String getName() {
    return name;
    }

    /**
    * @param name
    * the name to set
    */
    public void setName(String name) {
    this.name = name;
    }

    /**
    * @return the amount
    */
    public double getAmount() {
    return amount;
    }

    /**
    * @param amount
    * the amount to set
    */
    public void setAmount(double amount) {
    this.amount = amount;
    }

    /**
    * @return the associations
    */
    public Set getAssociations() {
    return associations;
    }

    /**
    * @param associations
    * the associations to set
    */
    public void setAssociations(Set associations) {
    this.associations = associations;
    }
    }

    /**
    package SampleJavaProject.Entity;

    import java.io.Serializable;

    /**
    * @author Siddhant_S
    *
    */
    @Entity
    @Table(name = “Person_Bank_Association”, schema = “test”)
    @AssociationOverrides({
    @AssociationOverride(name = “pk.person”, joinColumns = @JoinColumn(name = “person_id”)),
    @AssociationOverride(name = “pk.bank”, joinColumns = @JoinColumn(name = “bank_id”)) })
    public class PersonBankAssociation implements Serializable {
    @EmbeddedId
    private PersonBankId pk;
    private String name;
    private double amount;
    /**
    *
    */
    public PersonBankAssociation() {
    }
    /**
    * @param name
    * @param amount
    */
    public PersonBankAssociation(String name, double amount) {
    this.name = name;
    this.amount = amount;
    }
    /**
    * @return the pk
    */
    public PersonBankId getPk() {
    return pk;
    }
    /**
    * @param pk
    * the pk to set
    */
    public void setPk(PersonBankId pk) {
    this.pk = pk;
    }

    /**
    * @return the name
    */
    public String getName() {
    return name;
    }

    /**
    * @param name
    * the name to set
    */
    public void setName(String name) {
    this.name = name;
    }

    /**
    * @return the amount
    */
    public double getAmount() {
    return amount;
    }

    /**
    * @param amount
    * the amount to set
    */
    public void setAmount(double amount) {
    this.amount = amount;
    }

    /**
    *
    * @return person
    */
    @Transient
    public Person getPerson() {
    return getPk().getPerson();
    }

    public void setPerson(Person person) {
    getPk().setPerson(person);
    }

    /**
    *
    * @return bank
    */
    @Transient
    public Bank getBank() {
    return getPk().getBank();
    }

    public void setBank(Bank bank) {
    getPk().setBank(bank);
    }
    }

    /**
    package SampleJavaProject.Entity;

    import java.io.Serializable;

    /**
    * @author Siddhant_S
    *
    */
    @Embeddable
    public class PersonBankId implements Serializable {
    @ManyToOne
    private Person person;
    @ManyToOne
    private Bank bank;

    /**
    *
    */
    public PersonBankId() {
    }

    /**
    * @param person
    * @param bank
    */
    public PersonBankId(Person person, Bank bank) {
    this.person = person;
    this.bank = bank;
    }

    /**
    * @return the person
    */
    public Person getPerson() {
    return person;
    }

    /**
    * @param person
    * the person to set
    */
    public void setPerson(Person person) {
    this.person = person;
    }

    /**
    * @return the bank
    */
    public Bank getBank() {
    return bank;
    }

    /**
    * @param bank
    * the bank to set
    */
    public void setBank(Bank bank) {
    this.bank = bank;
    }

    }

    /**
    package SampleJavaProject.HibernateTransaction;

    import java.util.Calendar;

    /**
    * @author Siddhant_S
    *
    */
    public class PersonBankApp {
    private static final Logger _logger = LoggerFactory
    .getLogger(PersonBankApp.class);
    private static final Session session = HibernateUtil.getSessionFactory()
    .openSession();

    /**
    * @return the Logger
    */
    public static Logger getLogger() {
    return _logger;
    }

    /**
    * @return the session
    */
    public static Session getSession() {
    return session;
    }

    /**
    * @param args
    */
    public static void main(String[] args) {
    getSession().beginTransaction();
    Bank bank=new Bank(“SBI”, 2000.00);
    getSession().save(bank);
    Calendar birthDate=GregorianCalendar.getInstance();
    birthDate.setTime(new Date());
    Person person=new Person(“Siddhant”, 2000.00, birthDate, “lane4”);
    PersonBankAssociation associations=new PersonBankAssociation(“Sbi name”, 2000.00);
    associations.setPerson(person);
    associations.setBank(bank);
    person.getBank().add(associations);

    Integer personId= (Integer) getSession().save(person);
    getSession().getTransaction().commit();
    getSession().close();
    System.out.println(“Person id:”+personId);
    }

    }

  33. Hi Mkyong,

    I am new to hibernate, I learned most of the hibernate from your site. I am trying to implement above example with following scenario:

    Trying to update an existing record in stock_category table with existing stock and category. but without any success. Can you post an example for above scenario.
    Example:

    stock
    —–
    stock_id= 1
    stock_id=2

    category
    ———
    category_id=1
    category_id=2

    stock_category
    —————
    stock_id =1, category_id=1

    How can I update stock_category existing record as follows

    stock_id=1 and category_id=2

    Can you help me to resolve the above scenario. an example would be great.

    Thanks,
    Jk

  34. Hi mKyong,

    i am trying to set up a similar example but i want to insert values to the join table.

    Could you please update your example by giving an example how to insert a value to your join table having the IDs of the other 2 tables??
    Thanks 🙂

      1. I have the same issue. I need to delete the association… i tried to remove my StockCategory equivalent from collection on the Stock side and nothing happens.. i tried to remove directly the StockCategory using the entity manager and nothing happens…

        1. You need to update both sides of the link between Load and Session:

          Session session = sessionDao.getObject(sessionId);
          Load load = loadDao.getObject(loadId);

          load.getSessions().remove(session);
          session.getLoads().remove(load);
          loadDao.saveObject(load);

          Actually, many developer use defensive methods to manage bi-directional associations. For example on Load, you could add the following methods:

          public void removeFromSessions(Session session) {
          this.getSessions().remove(session);
          session.getLoads().remove(this);
          }
          public void addToSessions(Session session) {
          this.getSessions().add(session);
          session.getLoads().add(this);
          }

  35. Excellent tutorial, can you please write a tutorail with same example but using XML mappings

    Thanks a lot

    Mazhar Hassan

    1. I’ve researched. You can go to book “Hibernate In Action” page 229. It exposes how to do that.
      There are 3 classes: Category, Item and CategorizedItem

      Main things to do:

      public class CategorizedItem {
      private User user;
      private Date dateAdded;
      private Item item;
      private Category category;
      ….
      }

      In file mapping Category.hbm.xml

      ….

  36. Hi Mk,
    While updating association of Stock_Category, older record were not deleted.
    They exist with new records in STCOK_CATEGORY table.

  37. Your example allows to relate two Stock and Category instances. But how do you release (unlink) an existing relationship? It appears to me that the only way your code offers is by explicitely deleting the corresponding StockCategory object representing the link.

  38. There is a simpler way to implement this.
    reference : http://forum.springsource.org/showthread.php?126461-How-to-realize-a-many-to-many-relation-type-with-attributes
    Although the example is using spring roo however it is perfectly applicable to regular JPA entity.

    Here is the example:
    Join entity needs the following annotation to ensure that there are not two entries with the same composite (not primary) key (human, qualification)

    @RooJavaBean
    @RooToString
    @RooJpaActiveRecord
    @Table(uniqueConstraints=@UniqueConstraint(columnN ames={"human","qualification"}), name="myUniqueConstraint")
    public class HumanQualification {
    
    @ManyToOne
    private Human human;
    
    @ManyToOne
    private Qualification qualification;
    
    private Float weight;
    }
    

    In Human and Qualification there must be “orphanRemoval=true” to delete corresponding join entities if a Human or Qualification is deleted:

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "human", orphanRemoval=true)
    private Set<HumanQualification> humanQualification = new HashSet<HumanQualification>();
    

    Hope this simplifies the solution

  39. i run successfully but StockCategory not see. But…

    @Embeddable
    public class StockCategoryId implements java.io.Serializable {
     
    	private Stock stock;
        private Category category;
     
    	public Stock getStock() {
    		return stock;
    	}
     
    	public void setStock(Stock stock) {
    		this.stock = stock;
    	}
     
    	public Category getCategory() {
    		return category;
    	}
     
    	public void setCategory(Category category) {
    		this.category = category;
    	}
    

    when not “@ManyToOne” is have composite keys but haven’t relationship
    Please kindly help me. Thank you!!

  40. Hi I have used you example in my project:
    here goes the code:
    @Entity
    @Table(name=”RCPTDTL”)
    public class RcptDtl {

    @Column(name = “RCPTID”)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long rcptId;
    @Column(name=”SOURCE_NAME”)
    private String sourceName;
    @Column(name=”DISP_NAME”)
    private String dispName;
    @Id
    @Column(name=”SOURCE_CSI”)
    private String sourceCsi;
    @OneToMany(fetch = FetchType.LAZY, mappedBy = “src_MapID.rcpt”)
    private Collection sourceMap = new ArrayList();

    }

    public class SourceMap implements java.io.Serializable {
    //EXtra coulm
    @Id
    @Column(name=”MAPID”)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long mapId;
    @Column(name=”CREAT_DT”)
    private Date creatDt;
    @Column(name=”CREAT_BY”)
    private String creatBy;
    @Column(name=”UPD_DT”)
    private Date updDt;
    @Column(name=”UPD_BY”)
    private String updBy;
    @Column(name=”MAPVAL”)
    private String mapVal;
    //Extra coulm end
    @EmbeddedId
    private SourceMapID src_MapID = new SourceMapID();

    public SourceMapID getSrc_MapID() {
    return src_MapID;
    }

    public void setSrc_MapID(SourceMapID src_MapID) {
    this.src_MapID = src_MapID;
    }

    @Transient
    public PackageDtl getPackageDtl() {
    return getSrc_MapID().getPackageDtl();
    }
    public void setPackageDtl(PackageDtl packageDtl) {
    getSrc_MapID().setPackageDtl(packageDtl);
    }
    @Transient
    public RcptDtl getRcpt() {
    return getSrc_MapID().getRcpt();
    }
    }

    @Embeddable
    public class SourceMapID implements java.io.Serializable{

    private PackageDtl packageDtl;

    private RcptDtl rcpt;
    @ManyToOne
    public PackageDtl getPackageDtl() {
    return packageDtl;
    }
    public void setPackageDtl(PackageDtl packageDtl) {
    this.packageDtl = packageDtl;
    }
    @ManyToOne
    public RcptDtl getRcpt() {
    return rcpt;
    }
    public void setRcpt(RcptDtl rcpt) {
    this.rcpt = rcpt;
    }

    }

    @Entity
    @Table(name=”PACKAGEDTL”)
    public class PackageDtl {

    @Id
    @Column(name=”PID”)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long pId;
    @Column(name=”ROSETTAID”)
    private long rosettaId;
    @Column(name=”DEFNAME”)
    private String defname;
    @Column(name=”MASTERID”)
    private String masterId;
    @Column(name=”CREAT_DT”)
    private Date creatDt;
    @Column(name=”CREAT_BY”)
    private String creatBy;
    @Column(name=”UPD_DT”)
    private Date updDt;
    @Column(name=”UPD_BY”)
    private String updBy;
    @OneToMany(fetch = FetchType.LAZY, mappedBy = “src_MapID.packageDtl”)
    private Collection sourceMap = new ArrayList();
    }

    But getting exception :
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘bookDao’ defined in class path resource [application.xml]: Cannot resolve reference to bean ‘HibernateTemplate’ while setting bean property ‘template’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘HibernateTemplate’ defined in class path resource [application.xml]: Cannot resolve reference to bean ‘sessionFactory’ while setting bean property ‘sessionFactory’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘sessionFactory’ defined in class path resource [application.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.lexisnexis.rcpt.domain.SourceMap.src_MapID.rcpt in com.lexisnexis.rcpt.domain.RcptDtl.sourceMap

    Tried a lot but could not figure out what I am doing wrong ….

    1. Hi I am able to figure out the issue thanks a lot for your block it is wonder full.

      Do you have any example of binding java.util.collection member variable in spring form:form tag

      1. Hi I have one issue with you example in case of update all things are working good but the
        orphan object is not deleted after putting orphan=”true” also hibernate is not running the
        delete query.

        Any suggestion how the hibernate will delete the orphan object while updating will be really helpful …

        thanks
        Chandan

  41. I have a question. In the example 1 is the Stock the name “PADINI”. How I can change the name PADINI after session.getTransaction().commit();

  42. I liked this article which is pretty helpful. However, if I only want to map the name column in category talbe -ie. instead of Colleciton, I want Collection which is a list of catory name only. Is there anyway I can do that? An XML format would be highly appreciated.

    Many thanks,

  43. MKYOUNG, I am very thankful for your tutorials, Its helped me many times and thought to give you thanks at least. Keep up your working! Thanks again!

  44. Hello,

    I have following problem/question…I have been told that the orm could or increase scallability of the whole application. By increasing scallability i mean situation in which I add new data sets into tables or increase the complexity (perform sufisticated for example select based on i.e. join)and see that the time of the response of my application increases much less than in situation when I’d use jdbc. Please dont confuse that im trying to prove that jdbc is slover than orm…Can u put some comment to this. Im interested how in the best way show this in my app.

    Thx in advance.

    1. You should Google for more, just highlight brief compare between JDBC vs ORM :

      JDBC is simple, fast, and easy to learn. Good for simple application, bad for scalability and large system, because you hardcode the SQL, and the hardcode is just hard to maintain. And, you need to know SQL to write JDBC.

      ORM is easy to maintain, coz no more hardcode, you don’t need to know SQL to write code, and everything is Object. But, it is slightly slower than JDBC, and take time to learn if the table <-> data model is complex. When code in complex table relationship or large join, ORM is bad.

  45. Hello. Thanks for the great tutorial. What i was search all over was a nice example on how to update a many to many associated relationship. For example you have your stock with some category. Now you you remove some categories and add different ones. I didn’t manage to do it properly with hibernate.. 🙁 I got it to work that all categories where removed or where i suddenly had always doubled records. To be more precise, i didn’t used exactly your example but also i took it as reference for my code. It would be nice to see a code example where you see added/removed stuff. Anyway, thanks a lot again!! Cheers

  46. this tuto is to great, i transform it with attribute override to make one to many association with extra columns

  47. hi
    in your case you have check you many to one mappin
    when you choose class=” you r class” your class in not set to object yo define in getter setter
    have enjoy 😉

  48. Hi mkyong,

    This example works fine, but there’s a performance problem with Hibernate when you run a HQL like this:

    SELECT s
    FROM Stock s
    LEFT JOIN FETCH s.stockCategories cRel
    WHERE s.stockId = :id

    i.e. you want to fetch a stock with all its all categories in one SQL (avoiding n+1 selects)

    This fetch doesn’t work properly. Actually, it does the join and executes the correct SQL, but immediately after that, for each stock_category Hibernate executes additional SQLs to fetch the associated stock and category separately!!!

    I think it’s a bug in Hibernate that forces separate SQLs for each part of a composite PK if it’s entity type.

    Do you maybe know a workaround for this?

    Tnx,
    Dexy

  49. Hey Mkyong

    Great examples & tutorials!

    But I’m having some trouble adding another table to the jointable. Using your example what I need is to add lets say a table projects connected to the stock_category table.

    In my case stock is users and category is projects and the added table would be the number of hours worked on a specific project (using a date).

    A database example:
    http://i48.tinypic.com/4q1k48.png

    Any idea how I could do this?

    Cheers

    p00m

  50. Thanks for the great tutorial.

    One issue i’ve found when using this strategy is you might get a NullPointer when hibernate tries to set the id values in the EmbeddedId object. This comes out in the stack trace with the following exception –

    org.hibernate.PropertyAccessException: could not set a field value by reflection setter …..

    I solved it by constructing a blank EmbeddedId instance in the constructor of the class in which the id is embedded. In your example i’d add the following –

    public StockCategory() {
    pk = new StockCategoryId;
    }

  51. Hi , thanks for this tutorial I want the same solution but with xml , if u can help me thanks I searched at google and stackoverflow but i didnt found a solution

  52. New at Hibernate .. pardon my ignorance

    In the example that you have shown .. Is there a way to get set of Category for given stock entity or vice verse return set of Stock for given Category?

    Thanks
    Rakesh

  53. Using criteria for quering…

    DetachedCriteria criteria = DetachedCriteria.forClass(StockCategory.class,”stock-cat”);
    criteria.createAlias(“stock-cat.pk”,”p”);
    criteria.createAlias(“p.stock”,”st”);
    criteria.add(Restrictions.eq(“st.stockName”, “abc”);

    When this query run it throws:
    org.postgresql.util.PSQLException: ERROR: missing FROM-clause entry for table “st1_”

    what is wrong?

    thanks in advance!

  54. Can you give me some pointers on how to delete the mapping. I tried removing the StockCategory from the attached set and updating the Stock product. Though it updated without errors the records were not deleted from join table. My implementation is in spring.

    Essentially my code is

     
    Stock stock = loadStock(stockId)
    
    StockCategory associationToRemove = new StockCategory();
    associationToRemove.setStock(stock);
    associationToRemove.setCategory(loadCategory(catId));
    stock.getStockCategory().remove(associationToRemove);
    
    update(stock);
    

    Fetch and assign works as expected.

    Thanks!

  55. Dear Mr. MkYong,
    I frequently enjoy your blog and it has given me a number of solutions for problems. Thank you for using your time to share your knowledge!
    Having said that I was wondering whether this article’s initial statement:
    “The Hibernate / JBoss tools generated annotation codes are not working in this third table extra column scenario.”
    was really true.
    To clarify, I used the “JPA-Project” under Eclipse Java EE IDE for Web Developers “Indigo”, apparently a different tool(!?) but it ships with my Eclipse-version, so no need for an extrag plugin.
    My Hibernate Version is hibernate-distribution-3.5.0-Final with Java 1.6.
    I used your CREATE TABLE-SQL, adapting it for HSQLDB, and had Eclipse generate the Java classes.
    The most striking difference to your solution is the generated

    @Embeddable
    public class StockCategoryPK implements Serializable {
    	private int stockId;
    	private int categoryId;
            ...
    

    which, as one can see, only contains the keys of the Stock and Category-objects as opposed to the entire object-references in your solution.
    The latter are, seemingly superfluously, added to the StockCategory class as well by the code generation:

    @Entity
    @Table(name="STOCK_CATEGORY")
    public class StockCategory implements Serializable {
    	private static final long serialVersionUID = 1L;
    	private StockCategoryPK id;
    	private String createdBy;
    	private Date createdDate;
    	private Category category;//seems superfluous, but...
    	private Stock stock;//seems superfluous, but...
    

    However, I found that in order to make it work one has to assign ONLY the

            private StockCategoryPK id;
    

    -field
    and NOT the

    	private Category category;
    	private Stock stock;
    

    after a new Category- and Stock-Object respectively have been persisted first.
    A simple JPQL “select distinct sc from StockCategory sc” will reveal that the stock- and category-fields in all the StockCategory-objects are indeed assigned by JPA/Hibernate!
    So, to clarify, the entire persisting-sequence would be:

    Stock stock = new Stock();
    stock.setStockCode("7052");
    stock.setStockName("PADINI");
    manager.persist(stock);
    Category category1 = new Category("CONSUMER", "CONSUMER COMPANY");
    manager.persist(category1);
    StockCategory stockCategory = new StockCategory();
    stockCategory.setCreatedDate(new Date());
    stockCategory.setCreatedBy("system");
    StockCategoryPK scpk = new StockCategoryPK();
    scpk.setCategoryId(category1.getCategoryId());
    scpk.setStockId(stock.getStockId());
    stockCategory.setId(scpk);
    stock.getStockCategories().add(stockCategory);
    //optional:			        category1.getStockCategories().add(stockCategory);
    manager.persist(stockCategory);  
    System.out.println("Done");
    

    So that’s 16 lines of persist-code as opposed to your 13 lines.

    To me, that’s a tradeoff which should be carefully considered:
    a) The scenario is common in relational databases (doctor-treats-patient at a specific time and with a specific diagnosis, sportsteam-meets-sportsteam at a specific time with a endresult, etc…) and I would really like to use generated code for that.
    b)Your solution makes a number of changes necessary which are spread out over all the generated classes. Forgetting one is fatal, for instance:
    c) With your solution the cascade=CascadeType.ALL in

    public class Stock implements java.io.Serializable {
    ...
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.stock", cascade=CascadeType.ALL)
    	public Set<StockCategory> getStockCategories() {
    		return this.stockCategories;
    	}
    

    is mandatory for this to work (otherwise table STOCK_CATEGORY would be empty)
    In the generated code it isn’t!
    d) Accessing a Stock’s Category-objects via it StockCategory-Set is slightly easier in JPQL. With the generated code the query woud be:

    "select distinct c.category from Stock s join s.stockCategories c"
    

    With your solution it’s:

    "select distinct c.pk.category from Stock s join s.stockCategories c"
    

    e) Finally, the least important, but still: The Eclipse JPA-Project doesn’t recognize your solution and keeps flagging an error at design time. This error is only caused by the JPA-facette of Eclipse and doesn’t prevent the code from compiling and running, but it is annoying…
    I will gladly send you my entire Eclipse-project for your inspection, should you be interested and, since this is my first response to one of your articles, would be delighted if you commented it!
    Thank you for your time
    yours sincerely
    Chris457

    1. Hi Chris, Thanks for your long comment and i am really appreciated it, but my reply will be short 🙂

      Current JBoss tool generated codes are not able to fulfill my needs for third table which has extra columns, so i have to hack it. The way it handle the relationship is weird and may prompts warning in IDE, but it’s works at my end (so, who’s care?). In additional, i just can’t find any “standard” solution on Hibernate documentation.

      hehe… may be you should send a request to Hibernate team to ask them put a standard solution on Hibernate documentation.

  56. Hi,

    I’d like to get some feedback on this approach vs ManyToMany in relation to lazy loading and using Set. When you insert an item into a Set, in a @ManyToMany, usually the whole set will be loaded to ensure uniqueness. However, since the stockCategory represents the two ids of the related items, an equals comparison could be done solely based on the ids and the related entity should not have to load. Is this true? If so, would this work like this in the above example?

  57. Hello,
    Thankyou for taking the time to create/share the tutorial.

    I’ve tried to implement it in my Spring/Hibernate application but I seem to get some sort of object nesting recursion going when I make the call for fetch an object from one side of the relationship.

    I’ve detailed the problem/code on coderanch here:
    http://www.coderanch.com/t/560053/Spring/Spring-hibernate-manytomany-mapping-problems

    And on Spring Source here:
    http://forum.springsource.org/showthread.php?118938-Hibernate-manytomany-mappings

    I suspect it’s something silly/obvious but as a noob to Spring/Hibernate I’m struggling. If you could spare 10 minutes to have a quick look for anything obvious it would be much appreciated 🙂

  58. Hello,
    I used your ManyToMany example with additionnals columns in the join table with hibernate 3.6.1.
    – When I save the Stock entity with categories associated : All is Ok.
    – When I read the Stock entity : All is Ok.
    – When I delete The Stocke entity the joint table records are also removed : All is Ok
    – But when I update the Stock entity (without to change associated categories) Hibernate go to stack overflow error :

    java.lang.StackOverflowError
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:431)
    at com.mysql.jdbc.PreparedStatement.getInstance(PreparedStatement.java:872)
    at com.mysql.jdbc.ConnectionImpl.clientPrepareStatement(ConnectionImpl.java:1490)
    at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4253)
    at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4152)
    at org.hibernate.jdbc.AbstractBatcher.getPreparedStatement(AbstractBatcher.java:534)
    at org.hibernate.jdbc.AbstractBatcher.getPreparedStatement(AbstractBatcher.java:452)
    at org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java:161)
    at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1700)
    at org.hibernate.loader.Loader.doQuery(Loader.java:801)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
    at org.hibernate.loader.Loader.loadEntity(Loader.java:2037)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:86)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:76)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3293)
    at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:496)
    at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:477)
    at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:227)
    at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:285)
    at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:152)
    at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1090)
    at org.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1038)
    at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:630)
    at org.hibernate.type.EntityType.resolve(EntityType.java:438)
    at org.hibernate.type.ComponentType.resolve(ComponentType.java:617)
    at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:722)
    at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:606)
    at org.hibernate.loader.Loader.doQuery(Loader.java:829)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
    at org.hibernate.loader.Loader.loadEntity(Loader.java:2037)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:86)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:76)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3293)
    at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:496)
    at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:477)
    at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:227)
    at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:285)
    at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:152)
    at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1090)
    at org.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1038)
    at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:630)
    at org.hibernate.type.EntityType.resolve(EntityType.java:438)
    at org.hibernate.type.ComponentType.resolve(ComponentType.java:617)
    at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:722)
    at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:606)
    at org.hibernate.loader.Loader.doQuery(Loader.java:829)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
    at org.hibernate.loader.Loader.loadEntity(Loader.java:2037)

  59. Hello,

    I was looking at Case1 and I don’t see where category1.stockCategories is being updated.
    Maybe I am missing something ?

    Thanks

    John

  60. I followed the xml mapping as in the attached zip
    but when trying to persist object I got the following error

    In java when trying to save the object

    Stocks stock = new Stocks();
    		stock.setStockCode("7052");
    	    stock.setStockName("PADINI");
    	   // session().save(stock);
    	    
    	    Cat cat1 = new Cat();
    	    cat1.setName("consumer");
    	    cat1.setDesc("consumer company");
    	    //new category, need save to get the id first
    	    
    	    session().save(cat1);
    
          
    	    
    	    StockCategory stockCategory = new StockCategory();
    	    stockCategory.setCategoryId(cat1);
    	    stockCategory.setStockId(stock);
    	    stockCategory.setCreatedDate(new Date());
    	    stockCategory.setCreatedBy("user");
    	    
    	    stock.setStockCategories(new HashSet());
    	    
    	    StockCategoryId scId = new StockCategoryId();
    	    stock.getStockCategories().add(stockCategory);
    	    
    	    session().save(stock);
    

    Following hibernate error is generated

    org.springframework.orm.hibernate3.HibernateSystemException: 
       ids for this class must be manually assigned before calling save(): com.mkyong.ternary.StockCategory; 
       nested exception is org.hibernate.id.IdentifierGenerationException: 
       ids for this class must be manually assigned before calling save(): com.mkyong.ternary.StockCategory
    	org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:661)
    	org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
    

    Can you please help me to solve this issue

    1. The ids didn’t assign properly. Seeing your error description is rather hard to tell you what is the root caused. My advice is download this project, and run it without any modification, and then compare with yours.

      1. Dear MK Yong
        Thanks for the reply. I desperately looking for the solution of this problem.

        As you suggested, I download the code as it is and run.

        I have used the xml mapping, so I removed the annotation and I end up with following code. Actually I need a solution in xml-mapping so I removed the annoation.

        but still get the error. Pls see below

        public class Category implements java.io.Serializable {
        	private Integer categoryId;
        	private String name;
        	private String desc;
        	private Set stockCategories = new HashSet(0);
        	
        	public Category() {
        	}
        
        	public Category(String name, String desc) {
        		this.name = name;
        		this.desc = desc;
        	}
        
        	public Category(String name, String desc, Set stockCategories) {
        		this.name = name;
        		this.desc = desc;
        		this.stockCategories = stockCategories;
        	}
        
        	public Integer getCategoryId() {
        		return categoryId;
        	}
        
        	public void setCategoryId(Integer categoryId) {
        		this.categoryId = categoryId;
        	}
        
        	public String getName() {
        		return name;
        	}
        
        	public void setName(String name) {
        		this.name = name;
        	}
        
        	public String getDesc() {
        		return desc;
        	}
        
        	public void setDesc(String desc) {
        		this.desc = desc;
        	}
        
        	public Set getStockCategories() {
        		return stockCategories;
        	}
        
        	public void setStockCategories(Set stockCategories) {
        		this.stockCategories = stockCategories;
        	}
        	
        	
        	
        }
        
        public class Stock implements java.io.Serializable {
        	private Integer stockId;
        	private String stockCode;
        	private String stockName;
        	private Set stockCategories = new HashSet(0);
        	
        	
        	public Integer getStockId() {
        		return stockId;
        	}
        	public void setStockId(Integer stockId) {
        		this.stockId = stockId;
        	}
        	public String getStockCode() {
        		return stockCode;
        	}
        	public void setStockCode(String stockCode) {
        		this.stockCode = stockCode;
        	}
        	public String getStockName() {
        		return stockName;
        	}
        	public void setStockName(String stockName) {
        		this.stockName = stockName;
        	}
        	public Set getStockCategories() {
        		return stockCategories;
        	}
        	public void setStockCategories(Set stockCategories) {
        		this.stockCategories = stockCategories;
        	}
        	
        	
        }
        public class StockCategory implements java.io.Serializable {
        	private StockCategoryId pk = new StockCategoryId();
        	private Date createdDate;
        	private String createdBy;
        	
        	public StockCategory() {
        	}
        
        	public Stock getStock(){
        		return getPk().getStock();
        	}
        	
        	public void setStock(Stock stock) {
        		getPk().setStock(stock);
        	}
        	
        	public Category getCategory() {
        		return getPk().getCategory();
        	}
        
        	public void setCategory(Category category) {
        		getPk().setCategory(category);
        	}
        	public boolean equals(Object o) {
        		if (this == o)
        			return true;
        		if (o == null || getClass() != o.getClass())
        			return false;
        
        		StockCategory that = (StockCategory) o;
        
        		if (getPk() != null ? !getPk().equals(that.getPk())
        				: that.getPk() != null)
        			return false;
        
        		return true;
        	}
        
        	public int hashCode() {
        		return (getPk() != null ? getPk().hashCode() : 0);
        	}
        	public StockCategoryId getPk() {
        		return pk;
        	}
        
        	public void setPk(StockCategoryId pk) {
        		this.pk = pk;
        	}
        
        	public Date getCreatedDate() {
        		return createdDate;
        	}
        
        	public void setCreatedDate(Date createdDate) {
        		this.createdDate = createdDate;
        	}
        
        	public String getCreatedBy() {
        		return createdBy;
        	}
        
        	public void setCreatedBy(String createdBy) {
        		this.createdBy = createdBy;
        	}
        	
        	
        }
        public class StockCategoryId implements java.io.Serializable {
        
        	private Stock stock;
            private Category category;
            
            
        	public Stock getStock() {
        		return stock;
        	}
        	public void setStock(Stock stock) {
        		this.stock = stock;
        	}
        	public Category getCategory() {
        		return category;
        	}
        	public void setCategory(Category category) {
        		this.category = category;
        	}
        	public boolean equals(Object o) {
                if (this == o) return true;
                if (o == null || getClass() != o.getClass()) return false;
        
                StockCategoryId that = (StockCategoryId) o;
        
                if (stock != null ? !stock.equals(that.stock) : that.stock != null) return false;
                if (category != null ? !category.equals(that.category) : that.category != null)
                    return false;
        
                return true;
            }
        
            public int hashCode() {
                int result;
                result = (stock != null ? stock.hashCode() : 0);
                result = 31 * result + (category != null ? category.hashCode() : 0);
                return result;
            }
        
        }
        
        

        When I run the code

        Stock stock = new Stock();
        	        stock.setStockCode("7052");
        	        stock.setStockName("PADINI");
        	        
        	        
        	        Category category1 = new Category("CONSUMER", "CONSUMER COMPANY");
        	        //new category, need save to get the id first
        	        session.save(category1);
        	        
        	        
        	        StockCategory stockCategory = new StockCategory();
        	        
        	        stockCategory.setStock(stock);
        	        stockCategory.setCategory(category1);
        	        stockCategory.setCreatedDate(new Date());
        	        stockCategory.setCreatedBy("system");
        	        
        	        stock.getStockCategories().add(stockCategory);
        	        session.save(stock);
        			
        	        
        

        I got the following error

        Hibernate: insert into category (NAME, `DESC`) values (?, ?)
        Hibernate: insert into stock (STOCK_CODE, STOCK_NAME) values (?, ?)
        Hibernate: select stockcateg_.STOCK_ID, stockcateg_.CATEGORY_ID, stockcateg_.CREATED_DATE as CREATED3_5_, 
        stockcateg_.CREATED_BY as CREATED4_5_ from stock_category stockcateg_ where stockcateg_.STOCK_ID=? and stockcateg_.CATEGORY_ID=?
        1427 [http-8090-2] ERROR org.hibernate.property.BasicPropertyAccessor - IllegalArgumentException in class: com.mkyong.stock.Stock, getter method of property: stockId
        org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of com.mkyong.stock.Stock.stockId
        	at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:195)
        	at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:199)
        	at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:3605)
        	at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:3321)
        
          1. The Xml Mapping worked only if we do individual save like stock,category followed by StockCategory.

             
            
            session.beginTransaction();
            	 
            		Stock stock = new Stock();
            	        stock.setStockCode("7052");
            	        stock.setStockName("PADINI");
            	        stock.setStockId(10);
            	     session.save(stock);
            	        Category category1 = new Category(11,"CONSUMER", "CONSUMER COMPANY");
            	      // Category category2 = new Category(12,"INVESTMENT", "INVESTMENT COMPANY");
            	 
            	       session.save(category1);
            	        
            	 
            	      
            	        StockCategory stockcat=new StockCategory();
            	      stockcat.setStock(stock);
            	       stockcat.setCategory(category1);
            	        stockcat.setCreatedBy("me");
            	        stockcat.setCreatedDate(new Date());
            	        
            	        
            	        StockCategoryId stoc_Cat_id=new StockCategoryId();
            	        stoc_Cat_id.setCategoryId(category1.getCategoryId());
            	        stoc_Cat_id.setStockId(stock.getStockId());
            	        
            	        stockcat.setId(stoc_Cat_id);
            	        
            	 //  stock.getStockCategories().add(stockcat);
            	     //category1.getStockCategories().add(stockcat); 
            	        
            	     // session.save(stock);
            	        
            	        
            	 session.save(stockcat);
            	 
            		session.getTransaction().commit();
            
  61. Hello,

    Thanks for this example. I have errors on
    @AssociationOverrides({
    @AssociationOverride(name = “pk.stock”,
    joinColumns = @JoinColumn(name = “STOCK_ID”)),
    @AssociationOverride(name = “pk.category”,
    joinColumns = @JoinColumn(name = “CATEGORY_ID”)) })

    Errors are :
    – Persistent type of override attribute pk.stock cannot be resolved
    – Persistent type of override attribute pk.category cannot be resolved

    Any idea about this problem ?
    Thanks for your help

    1. hi, i had the same problem as you but it was because i used jpa. don’t use jpa to do it. use pure hibernate and the file hibernate.cfg.xml

  62. Hi Sir mKyong,

    Can you please help me? I want to join 3 tables in 1 join table. Ex. Table User, Application, and Role will be joined in a table User_App_Role containing IDs of each tables.

    I tried to follow your example and here is my codes:

    User.java

    	@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.cmUser")
    	public Collection getCMUserApplicationRole() {
    		return this.cmUserAppRole;
    	}
    
    	public void setCMUserApplicationRole(Collection cmUserAppRole) {
    		this.cmUserAppRole = cmUserAppRole;
    	}
    	
    	private Collection cmUserAppRole = new ArrayList(0);
    

    CMApplication.java

    	@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.cmApplication")
    	public Collection getCMUserApplicationRole() {
    		return this.cmUserAppRole;
    	}
    
    	public void setCMUserApplicationRole(Collection cmUserAppRole) {
    		this.cmUserAppRole = cmUserAppRole;
    	}
    	
    	private Collection cmUserAppRole = new ArrayList(0);

    CMRole.java

     
    	@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.cmRole")
    	public Collection getCMUserApplicationRole() {
    		return this.cmUserAppRole;
    	}
    
    	public void setCMUserApplicationRole(Collection cmUserAppRole) {
    		this.cmUserAppRole = cmUserAppRole;
    	}
    	
    	private Collection cmUserAppRole = new ArrayList(0);
    

    CMUserApplicationRole.java

     
    @Entity
    @Table(name = "CMUserApplicationRole")
    @AssociationOverrides({
    		@AssociationOverride(name = "pk.cmUser", joinColumns = @JoinColumn(name = "USER_ID")),
    		@AssociationOverride(name = "pk.cmApplication", joinColumns = @JoinColumn(name = "APPLICATION_ID")),
    		@AssociationOverride(name = "pk.cmRole", joinColumns = @JoinColumn(name = "ROLE_ID"))})
    

    	@EmbeddedId
    	public CMUserApplicationRoleId getPk() {
    		return pk;
    	}
    
    	public void setPk(CMUserApplicationRoleId pk) {
    		this.pk = pk;
    	}
    	
    	@Transient
    	public CMUser getCMUser() {
    		return getPk().getCMUser();
    	}
    	
    	public void setCMUser(CMUser cmUser) {
    		getPk().setCMUser(cmUser);
    	}
    	
    	@Transient
    	public CMApplication getCMApplication() {
    		return getPk().getCMApplication();
    	}
    	
    	public void setCMApplication(CMApplication cmApplication) {
    		getPk().setCMApplication(cmApplication);
    	}
    	
    	@Transient
    	public CMRole getCMRole() {
    		return getPk().getCMRole();
    	}
    	
    	public void setCMRole(CMRole cmRole) {
    		getPk().setCMRole(cmRole);
    	}
    

    CMUserApplicationRoleId.java

    	@ManyToOne
    	public CMUser getCMUser() {
    		return cmUser;
    	}
    	public void setCMUser(CMUser cmUser) {
    		this.cmUser = cmUser;
    	}
    	
    	@ManyToOne
    	public CMApplication getCMApplication() {
    		return cmApplication;
    	}
    	public void setCMApplication(CMApplication cmApplication) {
    		this.cmApplication = cmApplication;
    	}
    	
    	@ManyToOne
    	public CMRole getCMRole() {
    		return cmRole;
    	}
    	public void setCMRole(CMRole cmRole) {
    		this.cmRole = cmRole;
    	}
    	
    	private CMUser cmUser;
    	private CMApplication cmApplication;
    	private CMRole cmRole;
    

    When I tried to run the code:

    session.beginTransaction();
    session.save(user);
    session.save(app1);
    session.save(role1);
    
    CMUserApplicationRole cmUserAppRole = new CMUserApplicationRole();
    cmUserAppRole.setCMApplication(app1);
    cmUserAppRole.setCMRole(role1);
    cmUserAppRole.setCMUser(user);
    
    session.save(cmUserAppRole);
    session.getTransaction().commit();
    

    I got the ff error:

    org.hibernate.MappingException: Could not determine type for: java.util.Collection, at table: CM_ROLE, for columns: [org.hibernate.mapping.Column(cmUserAppRole)]

    Please kindly help me. Thank you!

    1. This error typically occurs when you are mixing “field” and “property” access strategy.
      From what you have pasted up there I cannot tell if you put the

      @Id

      annotation above the method or attribute, so make sure you only stick to one access strategy. 🙂

  63. Thanks, but you should not talk about Hibernate. THIS is JPA implemented using Hibernate. All of the code in this article would work using any other Java Persistence Api provider.

Leave a Comment

Your email address will not be published. Required fields are marked *