[{ALLOW view All}]
[{ALLOW edit Authenticated}]
!Mapping a many-to-many join table with extra column(s) using JPA
As of 23.02.2010
There seams to be only following two blogs in the web where this is described:
[boris.kirzner.info/blog/archives/2008/07/19|http://boris.kirzner.info/blog/archives/2008/07/19/hibernate-annotations-the-many-to-many-association-with-composite-key/]
[sieze.wordpress.com/2009/09/04|http://sieze.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table-with-extra-column-using-jpa/]
But this solution does not work with EclipseLink, because obvioulsy
EclipseLink does only allow simple Java types as primary key fields in the Embeddable class.
I am still a newby in JPA and had some difficulties to solve it,
so I tried to use some tools:
!Database Tools
Though owned by Oracle now, I still use MySql. My choice for
designing tables and relations\\
is [MySql Workbench|http://www.mysql.de/products/workbench/]. You can easily syncronize your model with the database (Menu > Database).\\
So I "Reverse Engineer..." my few database tables so far into a new model,
changed it and "Synchronize Model..." back to the database.\\
To validate what happens on the database
I used additionally [Squirrel|http://squirrel-sql.sourceforge.net/] for SQL.
!Eclipse
In Eclipse you can create a "JPA Project". This comes from a project
called [Dali|http://www.eclipse.org/webtools/dali/] and is
part of the WTP (Web Tools Plattform).
You can update Eclipse with following update source:\\
__http://download.eclipse.org/webtools/updates/__
Please make sure to use the latest Dali update, otherwise it will not create the additional properties in the join table (see below)!
When you created a JPA Project, you can find \\
__Context Menu > New > Entities From Table__
Then a wizard comes up, where you can select your table and adjust
your mappings. Then Eclipse created all entity classes with
all annotations. Perfect stuff - now I don't need to rack my brain about this!\\
The nice thing is that you can test various models and see how this would look with JPA.
I tried also the model from the links above and this came out.\\
"color", "isAdmin" and "name" are the (stupid) additional properties\\
in ProductItem.
!Item
[{Java2HtmlPlugin
package ebel;
import java.io.Serializable;
import javax.persistence.*;
import java.util.List;
/**
* The persistent class for the item database table.
*
*/
@Entity
@Table(name="item")
public class Item implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name="ITEM_ITEMID_GENERATOR" )
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="ITEM_ITEMID_GENERATOR")
@Column(name="item_id")
private int itemId;
private String name;
//bi-directional many-to-one association to ProductItem
@OneToMany(mappedBy="item")
private List<ProductItem> productItems;
public Item() {
}
public int getItemId() {
return this.itemId;
}
public void setItemId(int itemId) {
this.itemId = itemId;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public List<ProductItem> getProductItems() {
return this.productItems;
}
public void setProductItems(List<ProductItem> productItems) {
this.productItems = productItems;
}
}
}]
!Product
[{Java2HtmlPlugin
package ebel;
import java.io.Serializable;
import javax.persistence.*;
import java.util.List;
/**
* The persistent class for the product database table.
*
*/
@Entity
@Table(name="product")
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
private int productId;
private String name;
private List<ProductItem> productItems;
public Product() {
}
@Id
@SequenceGenerator(name="PRODUCT_PRODUCTID_GENERATOR" )
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PRODUCT_PRODUCTID_GENERATOR")
@Column(name="product_id")
public int getProductId() {
return this.productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
//bi-directional many-to-one association to ProductItem
@OneToMany(mappedBy="product")
public List<ProductItem> getProductItems() {
return this.productItems;
}
public void setProductItems(List<ProductItem> productItems) {
this.productItems = productItems;
}
}
}]
!ProductItem
[{Java2HtmlPlugin
package ebel;
import java.io.Serializable;
import javax.persistence.*;
/**
* The persistent class for the product_item database table.
*
*/
@Entity
@Table(name="product_item")
public class ProductItem implements Serializable {
private static final long serialVersionUID = 1L;
private ProductItemPK id;
private String color;
private byte isAdmin;
private String name;
private Item item;
private Product product;
public ProductItem() {
}
@EmbeddedId
public ProductItemPK getId() {
return this.id;
}
public void setId(ProductItemPK id) {
this.id = id;
}
public String getColor() {
return this.color;
}
public void setColor(String color) {
this.color = color;
}
public byte getIsAdmin() {
return this.isAdmin;
}
public void setIsAdmin(byte isAdmin) {
this.isAdmin = isAdmin;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
//bi-directional many-to-one association to Item
@ManyToOne
@JoinColumn(name="item_id")
public Item getItem() {
return this.item;
}
public void setItem(Item item) {
this.item = item;
}
//bi-directional many-to-one association to Product
@ManyToOne
@JoinColumn(name="product_id")
public Product getProduct() {
return this.product;
}
public void setProduct(Product product) {
this.product = product;
}
}
}]
!ProductItemPk
[{Java2HtmlPlugin
package ebel;
import java.io.Serializable;
import javax.persistence.*;
/**
* The primary key class for the product_item database table.
*
*/
@Embeddable
public class ProductItemPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
private int itemId;
private int productId;
public ProductItemPK() {
}
@Column(name="item_id")
public int getItemId() {
return this.itemId;
}
public void setItemId(int itemId) {
this.itemId = itemId;
}
@Column(name="product_id")
public int getProductId() {
return this.productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ProductItemPK)) {
return false;
}
ProductItemPK castOther = (ProductItemPK)other;
return
(this.itemId == castOther.itemId)
&& (this.productId == castOther.productId);
}
public int hashCode() {
final int prime = 31;
int hash = 17;
hash = hash * prime + this.itemId;
hash = hash * prime + this.productId;
return hash;
}
}
}]