To define a one-to-many relationship, the following annotation is used @OneToMany.
The Interface with parameters and default values:
@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface OneToMany {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fetch() default LAZY;
String mappedBy() default "";
boolean orphanRemoval() default false;
}
where:
One-to-Many association using generics
@OneToMany(cascade=ALL, mappedBy="customer", orphanRemoval=true)
public Set<Order> getOrders() { return orders; }
@ManyToOne
@JoinColumn(name="CUST_ID", nullable=false)
public Customer getCustomer() { return customer; }
One-to-Many association without using generics
@OneToMany(
targetEntity=com.acme.Order.class,
cascade=ALL,
mappedBy="customer",
orphanRemoval=true
)
public Set getOrders() { return orders; }
@ManyToOne
@JoinColumn(name="CUST_ID", nullable=false)
protected Customer customer;
@OneToMany(orphanRemoval=true)
@JoinColumn(name="CUST_ID") // join column is in table for Order
public Set<Order> getOrders() {return orders;}
The @JoinColumn avoid to generate a join table in JPA 2.0
The data model is the following:
HELLO_ID | HELLO_DESC |
---|---|
1 | Hello Nico ! |
CAT_DESC | HELLO_ID |
---|---|
A normal Hello | 1 |
One Hello has severals hello Categories.
With an unidirectional metamodel model.
import javax.persistence.*;
import java.io.Serializable;
/**
* Represents an hello Category
*/
@Entity
@Table(name="HELLO_CAT")
public class HelloCategory implements Serializable {
@Id
@Column(name = "CAT_DESC")
private String desc;
@Id
// If the join column is not define, it will default to class+id column (HELLO_WORLD_ID)
// and you will get a ORA-00904 invalid identifier
// JoinColumn defines the name of the column in the table Hello_Cat
@JoinColumn(name= "HELLO_ID")
private HelloWorld helloWorld;
public HelloCategory() {
}
public HelloCategory(HelloWorld helloWorld) {
this.setHelloWorld(helloWorld);
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public HelloWorld getHelloWorld() {
return helloWorld;
}
public void setHelloWorld(HelloWorld helloWorld) {
this.helloWorld = helloWorld;
}
@Override
public String toString() {
return "HelloCategory{" +
"desc='" + desc + '\'' +
"helloWorld="+helloWorld.getDescription()+
'}';
}
}
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "HELLO")
public class HelloWorld implements Serializable {
@Id
@Column(name = "HELLO_ID", unique = true, nullable = false, updatable=false)
private String id;
@Basic()
@Column(name = "HELLO_DESC")
private String Description;
@OneToMany(orphanRemoval=true)
// The join column is in the many/target table (ie the HelloCategory)
// and is mandatory in order to not create a Join table (many-to-many structure).
@JoinColumn(name="HELLO_ID")
private List<HelloCategory> helloCategories = new ArrayList<HelloCategory>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public void add(HelloCategory helloCategory) {
//To change body of created methods use File | Settings | File Templates.
getHelloCategories().add(helloCategory);
}
public List<HelloCategory> getHelloCategories() {
return helloCategories;
}
@Override
public String toString() {
return "HelloWorld{" +
"id='" + id + '\'' +
", Description='" + Description + '\'' +
", helloCategories=" + helloCategories +
'}';
}
}
With JPA EclipseLink as persistence provider.
persistence.xml file
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="PersistenceUnitName" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>HelloWorld</class>
<class>HelloCategory</class>
</persistence-unit>
</persistence>
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.config.TargetDatabase;
import org.eclipse.persistence.logging.SessionLog;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map props = new HashMap();
props.put(PersistenceUnitProperties.JDBC_USER, "sh");
props.put(PersistenceUnitProperties.JDBC_PASSWORD, "sh");
props.put(PersistenceUnitProperties.TARGET_DATABASE, TargetDatabase.Oracle11);
props.put(PersistenceUnitProperties.JDBC_DRIVER,"oracle.jdbc.OracleDriver");
props.put(PersistenceUnitProperties.JDBC_URL,"jdbc:oracle:thin:@localhost:1521/pdborcl.hotitem.local");
props.put(PersistenceUnitProperties.LOGGING_LEVEL, SessionLog.FINE_LABEL);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersistenceUnitName", props);
EntityManager em = emf.createEntityManager();
// A normal Hello World Construction
// The normal Hello World
HelloWorld aNormalHelloWorld = new HelloWorld();
aNormalHelloWorld.setId("1");
aNormalHelloWorld.setDescription("Hello Nico !");
// The normal Hello Category
HelloCategory aNormalHelloCategory = new HelloCategory(aNormalHelloWorld);
aNormalHelloCategory.setDesc("A normal Hello");
aNormalHelloWorld.add(aNormalHelloCategory);
// Persistence
em.getTransaction().begin();
em.merge(aNormalHelloWorld);
em.getTransaction().commit();
// Retrieve
// Hello World whose primary key is 1
HelloWorld helloWorld = em.find(HelloWorld.class, "1");
System.out.println(helloWorld);
for (HelloCategory helloCategory:helloWorld.getHelloCategories()){
System.out.println(helloCategory.getDesc());
}
em.close();
emf.close();
}
}
[EL Config]: metadata: 2013-12-22 17:49:43.495--ServerSession(1293031597)--Thread(Thread[main,5,main])
--The access type for the persistent class [class HelloCategory] is set to [FIELD].
[EL Config]: metadata: 2013-12-22 17:49:43.522--ServerSession(1293031597)--Thread(Thread[main,5,main])
--The element [field helloWorld] is being defaulted to a one to one mapping.
[EL Config]: metadata: 2013-12-22 17:49:43.524--ServerSession(1293031597)--Thread(Thread[main,5,main])
--The element [field helloWorld] is being defaulted to a one to one mapping.
[EL Config]: metadata: 2013-12-22 17:49:43.531--ServerSession(1293031597)--Thread(Thread[main,5,main])
--The target entity (reference) class for the one to one mapping element [field helloWorld] is being defaulted to: class HelloWorld.
[EL Config]: metadata: 2013-12-22 17:49:43.532--ServerSession(1293031597)--Thread(Thread[main,5,main])
--The access type for the persistent class [class HelloWorld] is set to [FIELD].
[EL Config]: metadata: 2013-12-22 17:49:43.538--ServerSession(1293031597)--Thread(Thread[main,5,main])
--The target entity (reference) class for the one to many mapping element [field helloCategories] is being defaulted to: class HelloCategory.
[EL Config]: metadata: 2013-12-22 17:49:43.539--ServerSession(1293031597)--Thread(Thread[main,5,main])
--The alias name for the entity class [class HelloCategory] is being defaulted to: HelloCategory.
[EL Config]: metadata: 2013-12-22 17:49:43.565--ServerSession(1293031597)--Thread(Thread[main,5,main])
--The alias name for the entity class [class HelloWorld] is being defaulted to: HelloWorld.
[EL Config]: metadata: 2013-12-22 17:49:43.58--ServerSession(1293031597)--Thread(Thread[main,5,main])
--The primary key column name for the mapping element [field helloWorld] is being defaulted to: HELLO_ID.
[EL Warning]: metadata: 2013-12-22 17:49:43.581--ServerSession(1293031597)--Thread(Thread[main,5,main])
--You have specified multiple ids for the entity class [HelloCategory] without specifying an @IdClass. By doing this you may lose the ability to find by identity, distributed cache support etc. Note: You may however use entity manager find operations by passing a list of primary key fields. Else, you will have to use JPQL queries to read your entities. For other id options see @PrimaryKey.
[EL Config]: metadata: 2013-12-22 17:49:43.598--ServerSession(1293031597)--Thread(Thread[main,5,main])
--The primary key column name for the mapping element [field helloCategories] is being defaulted to: HELLO_ID.
[EL Info]: 2013-12-22 17:49:44.238--ServerSession(1293031597)--Thread(Thread[main,5,main])
--EclipseLink, version: Eclipse Persistence Services - 2.5.2.v20131113-a7346c6
[EL Config]: connection: 2013-12-22 17:49:44.246--ServerSession(1293031597)--Connection(1340160707)--Thread(Thread[main,5,main])
--connecting(DatabaseLogin(
platform=>Oracle11Platform
user name=> "sh"
datasource URL=> "jdbc:oracle:thin:@localhost:1521/pdborcl.hotitem.local"
))
[EL Config]: connection: 2013-12-22 17:49:44.717--ServerSession(1293031597)--Connection(1524017553)--Thread(Thread[main,5,main])
--Connected: jdbc:oracle:thin:@localhost:1521/pdborcl.hotitem.local
User: SH
Database: Oracle Version: Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
Driver: Oracle JDBC driver Version: 11.1.0.7.0-Production
[EL Info]: connection: 2013-12-22 17:49:44.785--ServerSession(1293031597)--Thread(Thread[main,5,main])
--file:/D:/svn_obiee-utility-plus/target/classes/_PersistenceUnitName_url=jdbc:oracle:thin:@localhost:1521/pdborcl.hotitem.local_user=sh login successful
[EL Fine]: sql: 2013-12-22 17:49:44.848--ServerSession(1293031597)--Connection(1524017553)--Thread(Thread[main,5,main])
--SELECT HELLO_ID, HELLO_DESC FROM HELLO WHERE (HELLO_ID = ?)
bind => [1]
[EL Fine]: sql: 2013-12-22 17:49:44.988--ServerSession(1293031597)--Connection(1524017553)--Thread(Thread[main,5,main])
--SELECT CAT_DESC, HELLO_ID FROM HELLO_CAT WHERE (HELLO_ID = ?)
bind => [1]
[EL Fine]: sql: 2013-12-22 17:49:44.996--ServerSession(1293031597)--Connection(1524017553)--Thread(Thread[main,5,main])
--SELECT CAT_DESC, HELLO_ID FROM HELLO_CAT WHERE ((CAT_DESC = ?) AND (HELLO_ID = ?))
bind => [A normal Hello, 1]
[EL Fine]: sql: 2013-12-22 17:49:45.006--ClientSession(2069097123)--Connection(1524017553)--Thread(Thread[main,5,main])
--INSERT INTO HELLO_CAT (CAT_DESC, HELLO_ID) VALUES (?, ?)
bind => [A normal Hello, 1]
[EL Fine]: sql: 2013-12-22 17:49:45.008--ClientSession(2069097123)--Connection(1524017553)--Thread(Thread[main,5,main])
--UPDATE HELLO_CAT SET HELLO_ID = ? WHERE ((HELLO_ID = ?) AND (CAT_DESC = ?))
bind => [1, 1, A normal Hello]
[EL Fine]: sql: 2013-12-22 17:49:45.01--ClientSession(2069097123)--Connection(1524017553)--Thread(Thread[main,5,main])
--DELETE FROM HELLO_CAT WHERE ((CAT_DESC = ?) AND (HELLO_ID = ?))
bind => [A normal Hello 2, 1]
HelloWorld{id='1', Description='Hello Nico !', helloCategories={[HelloCategory{desc='A normal Hello'helloWorld=Hello Nico !}]}}
A normal Hello
[EL Config]: connection: 2013-12-22 17:49:45.054--ServerSession(1293031597)--Connection(1524017553)--Thread(Thread[main,5,main])
--disconnect
[EL Info]: connection: 2013-12-22 17:49:45.055--ServerSession(1293031597)--Thread(Thread[main,5,main])--
file:/D:/svn_obiee-utility-plus/target/classes/_PersistenceUnitName_url=jdbc:oracle:thin:@localhost:1521/pdborcl.hotitem.local_user=sh logout successful
[EL Config]: connection: 2013-12-22 17:49:45.056--ServerSession(1293031597)--Connection(1340160707)--Thread(Thread[main,5,main])
--disconnect