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“.
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.

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.

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.

Thanks a lot for the example Mkyong!
It been worked with also EntityManager!
Cheers.
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.
@Manoj for xml mapping view this:
http://www.skill-guru.com/blog/2010/02/10/mapping-composite-keys-in-hibernate/
hope it will help!!
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)
In Human and Qualification there must be “orphanRemoval=true” to delete corresponding join entities if a Human or Qualification is deleted:
Hope this simplifies the solution
i run successfully but StockCategory not see. But…
when not “@ManyToOne” is have composite keys but haven’t relationship
Please kindly help me. Thank you!!
nice explanation
Awesome, it works! Thank you!
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 ….
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
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
Hey..How did you resolve this error?
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();
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,
This is probably a better/nicer way to do this: http://stackoverflow.com/questions/5127129/mapping-many-to-many-association-table-with-extra-columns
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!
Hi,
Could you can provide the same example using xml mapping file?
thanks,
Pradeep
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.
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.
Nice article, I have an issue with multiple foreign keys, your language is understandable, could you please check it https://forum.hibernate.org/viewtopic.php?f=1&t=1016943
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
Where is the tutorial? I see only a bunch of unreadable code. What do those lines of code mean?
this tuto is to great, i transform it with attribute override to make one to many association with extra columns
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 ;)
I suggest logging a bug with Hibernate on this
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
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
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;
}
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
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
Mkyong, I posted a question to StackOverflow regarding this tutorial with my custom requirements. Would you mind taking a look when you have a chance? http://stackoverflow.com/questions/9549294/looping-through-hibernate-many-to-many-in-jsp I’ve been battling with this for about a week. Thanks for your helpful blog!
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!
Well I got the assocition, but how query a extra field from de join class using Criteria?
Thanks for your help
How do you persist a stockCategory instance getting an existing stock and an existing category?
Thanks in advance!
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
Fetch and assign works as expected.
Thanks!
Got it. Had to delete my association explicitly
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
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:
However, I found that in order to make it work one has to assign ONLY the
-field
and NOT the
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:
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
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:
With your solution it’s:
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
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.
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?
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 :)
I have the same problem. Did you solve the problem?
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)
I have exactly the same issue in hibernate4. Were you able to resolve this?
Hello,
I was looking at Case1 and I don’t see where category1.stockCategories is being updated.
Maybe I am missing something ?
Thanks
John
Useful example for many to many
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
Following hibernate error is generated
Can you please help me to solve this issue
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.
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
When I run the code
I got the following error
I didn’t test it with XML mapping, caused quite complicated to implement this in XML way, is the annotation version working?
yes, that was fine. But I need to work with xml mapping and i could not found anywhere on google :(
This kind of model is quite complicated to configure in XML mapping….hmm…
Try post your question on https://forum.hibernate.org/ or http://stackoverflow.com/ , update me if you have answer :)
The Xml Mapping worked only if we do individual save like stock,category followed by StockCategory.
Can you please tell me which tutorial?
I need xml mapping for many-to-many with extra columns.
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
Is this compile error? or runtime error?
Exampled tested in Hibernate 3.6, Eclipse 3.6, Maven3 and JDK1.6
It is a compile error.
Eclipse 3.7, JDK 1.6, Hibernate-JPA 2.0
At least post your compile error message for debug :)
Errors are listed on my first post :)
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
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
CMApplication.java
CMRole.java
CMUserApplicationRole.java
…
CMUserApplicationRoleId.java
When I tried to run the code:
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!
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
annotation above the method or attribute, so make sure you only stick to one access strategy. :)
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.
Should be JPA annotation in Hibernate project
What id stock_category table has one more column stockcategoryid as primary key??