Olimpiu POP
Olimpiu POP

Reputation: 5067

JPA 2.0 Bidirectional OneToOne doesn't create FK Column in DB

I have two very simple JPA entities that I used for learning purposes. Now, I tried to create a bidirectional one-to-one relation, but at DB level only the connection on the Employee side is created:

ID PARKINGSPACE_ID

While on the PARKINGSPACE side this is what's created

ID

I'm sorry if this is trivial question but I really don't see what's wrong. I tried to add the target entity on the parking space side, making both sides of the relation mandatory. I used the relation in other cases also, without problems. But I want to understand what's the problem here.

I use JPA 2.0 with hibernate 4.1.7 as provider and H2 as the underlying DB. Everything is run in the Java SE env.

@Entity
public class Employee {
   @Id
   @GeneratedValue
   private int id;

   @OneToOne
   private ParkingSpace parkingSpace;

   //...
}

@Entity
public class ParkingSpace {
    @Id
    @GeneratedValue
    private int id;

   @OneToOne(mappedBy = "parkingSpace")
   private Employee employee; 

   //..
}

persistence.xml

 <?xml version="1.0" encoding="UTF-8"?>
 <persistence version="2.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_2_0.xsd">
    <persistence-unit name="MenusService" transaction-type="RESOURCE_LOCAL">
        <properties>
            <!-- JPA specific -->
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost//d:/apps/h2/db/menus;MVCC=TRUE"/>

            <!-- JPA provider specific -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
      </properties>
</persistence-unit>

There are some errors in the console:

ERROR: Table "EMPLOYEE" not found; SQL statement: alter table Employee drop constraint FK4AFD4ACE384A747F [42102-168]

Upvotes: 1

Views: 597

Answers (2)

Ashish Modak
Ashish Modak

Reputation: 1

You did not get the meaning of Bidirectional in JPA.

It does not mean that it will create foreign keys on the both tables and actually only one foreign key is sufficient to create a join. In your case

SELECT e.* from EMPLOYEE e INNER JOIN PARKINGSPACE p ON e.PARKINGSPACE_ID=p.ID

SELECT p.* from PARKINGSPACE p INNER JOIN EMPLOYEE e ON p.ID=e.PARKINGSPACE_ID

so in this case we don't require a fk in PARKINGSPACE table. The bidirectional in JPA means we have the reference of both the entities in each one i.e while fetching one entity jpa can also fetch other relational entity.

In your case while fetching Employee you will automatically get Parkingspace entity and vice versa since you are using one to one relationship which is by default eager fetch.

Upvotes: 0

JB Nizet
JB Nizet

Reputation: 691775

You don't need two foreign keys in the database to materialize a single association. One is sufficient.

To get the parking space of a given employee, you look for the row in the parking space table which has the ID equal to the PARKINGSPACE_ID of the given employee.

To get the employee given a parking space, you look for the row in the employee table which has the PARKINGSPACE_ID equal to the ID if the given parking space.

If there were two foreign keys, the parking space could reference an employee which would reference another parking space, leaving the database in an incoherent state.

Upvotes: 4

Related Questions