In this article we will learn how to implement a One to Many Entity Relation between two objects in an Hibernate/JPA application.
One to Many overview
In RDBMS terms, a one-to-many relationship exists when one record in table A may be linked with many records in table B. On the other hand, one record in table B is linked to only one Record in table A.
Here’s an example which uses a One-to-Many mapping between the Table Customer (ONE) and Request (MANY).
For the sake of simplicity, we will use H2 Database in our example application. On the other hand, if you want to use an external DB like MySQL, you can create the following Table structure for the example:
mysql> desc customer; +--------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(25) | YES | | NULL | | | phone_number | int(11) | YES | | NULL | | | address | varchar(100) | YES | | NULL | | | email | varchar(50) | YES | | NULL | | +--------------+--------------+------+-----+---------+----------------+ 5 rows in set (0.07 sec) mysql> desc request; +-------------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | quantity | int(11) | YES | | NULL | | | id_customer | int(11) | YES | MUL | NULL | | +-------------+---------+------+-----+---------+----------------+
Coding the Entity Classes
To represent the One to Many Relation, we will create two Entity Classes in our project. Here’s the Customer class:
@Entity public class Customer implements Serializable { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @NotNull private String name; @NotNull private String email; @NotNull private String address; @NotNull @Column(name = "phone_number") private String phoneNumber; //bi-directional many-to-one association to Request @OneToMany(mappedBy="customer", cascade = CascadeType.ALL, orphanRemoval = true) private List<Request> requests = new ArrayList(); // getters/setters omitted for brevity }
Next, let’s add also the Request class:
@Entity public class Request implements Serializable { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @Column private int quantity; //bi-directional many-to-one association to Customer @ManyToOne private Customer customer; }
As you can see, in this example the Bidirectional Many to One annotation is explicit also in the target Entity Class.
We can persist and fetch data with this simple Stateless Bean:
@Stateless public class ServiceBean { @PersistenceContext private EntityManager em; public String create() { Customer customer = new Customer(); customer.setAddress("15th Avenue New York"); customer.setName("John Smith"); customer.setPhoneNumber("328/1145678"); customer.setEmail("[email protected]"); Request request = new Request(); request.setCustomer(customer); request.setQuantity(125); List<Request> list = new ArrayList(); list.add(request); customer.setRequests(list); em.persist(customer); return "Created!"; } public List<Request> findAll() { Query query = em.createQuery("FROM Request"); List<Request> list = query.getResultList(); return list; } }
In order to use the default H2 Database, we will include in the persistence.xml a reference to the ExampleDS Datasource:
<persistence-unit name="primary"> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <properties> <!-- Properties for Hibernate --> <property name="hibernate.hbm2ddl.auto" value="create-drop" /> <property name="hibernate.show_sql" value="true" /> </properties> </persistence-unit>
AnnotationException: @Column(s) not allowed on a @ManyToOne property
This error can happen if you use @JoinColumn and @Column annotation together.
@ManyToOne @Column(name="CustomerFK") private Customer customer;
It will return the following error:
org.hibernate.AnnotationException: @Column(s) not allowed on a @ManyToOne property
You can apply the JPA @Column annotation only for basic entity attributes (e.g. String, Integer, Date) if the entity attribute name differs from the underlying column name.
In the above example, you should rather use the @JoinColumn annotation:
@ManyToOne(fetch=FetchType.LAZY) @JoinColumn(name="CustomerFK") private Customer customer;
The @JoinColumn annotation allows to customize a Foreign Key column name, and it can only be used with an entity association.
Source code for this tutorial is available here: https://github.com/fmarchioni/mastertheboss/tree/master/hibernate/OneToMany