I'm using EclipseLink 2.5.1 (and Hibernate 4.3.5 final). Given the following tables in MySQL.
There is a many-to-many relationship between products and their colours.
A product can have many colours and a colour can in turn be associated with many products. This relationship is expressed in the database by these tables.
The prod_colour
table has two reference columns prod_id
and colour_id
from its related parent tables product
and colour
respectively.
As obvious, the entity class Product
has a list of colours - java.util.List<Colour>
which is named colourList
.
The entity class Colour
has a list of products - java.util.List<Product>
which is named productList
.
The relationship in the Colour
entity :
public class Colour implements Serializable {
@JoinTable(name = "prod_colour", joinColumns = {
@JoinColumn(name = "colour_id", referencedColumnName = "prod_id")}, inverseJoinColumns = {
@JoinColumn(name = "prod_id", referencedColumnName = "colour_id")})
@ManyToMany(mappedBy = "colourList", fetch = FetchType.LAZY)
private List<Product> productList; //Getter and setter.
//---Utility methods---
//Add rows to the prod_colour table.
public void addToProduct(Product product) {
this.getProductList().add(product);
product.getColourList().add(this);
}
//Delete rows from the prod_colour table.
public void removeFromProduct(Product product) {
this.getProductList().remove(product);
product.getColourList().remove(this);
}
}
The relationship in the Product
entity :
public class Product implements Serializable {
@JoinTable(name = "prod_colour", joinColumns = {
@JoinColumn(name = "prod_id", referencedColumnName = "prod_id")}, inverseJoinColumns = {
@JoinColumn(name = "colour_id", referencedColumnName = "colour_id")})
@ManyToMany(fetch = FetchType.LAZY)
private List<Colour> colourList; //Getter and setter.
}
From the associated EJB, the insert operation is performed as follows.
@Override
@SuppressWarnings("unchecked")
public boolean insert(List<Colour> colours, Product product)
{
int i=0;
Long prodId=product.getProdId();
for(Colour colour:colours)
{
Product p = entityManager.getReference(Product.class, prodId);
colour.addToProduct(p);
if(++i%49==0)
{
entityManager.flush();
}
entityManager.merge(colour);
entityManager.merge(p);
}
return true;
}
Everything works fine.
When duplicate rows are attempted (same Colour
entities associated with the same Product
entity), they are also inserted into the prod_colour
table that I expect should not happen.
Do I need to perform some extra conditional checks to avoid duplicate insertion or EclipseLink/Hibernate have some mechanism to prevent duplicates in such situations?
It's also surprising for me. I always was thinking that it made reference columns in join table as composite primary key, but it does not. If you want to have unique records try use Set
instead of List
or create your own ManyToMany relationship table with composite primary key(color_id, product_id). I don't have better idea.