Should JPA provider (Hibernate/Eclipselink) put unique constraint in unidirectional one to one relationship?

StackOverflow https://stackoverflow.com/questions/23392423

  •  12-07-2023
  •  | 
  •  

質問

I started to learn about JPA 2.1 and I'm reading now aboult relationships.

There is unidirectional One-to-one relationship, defined in JSR-338 as follow (section 2.10.3.1 "Unidirectional OneToOne Relationshps"):

The following mapping defaults apply:

  • Entity A is mapped to a table named A.
  • Entity B is mapped to a table named B.

Table A conttains a foreign key to table B. The foreign key column name is formed as the concatenation of the following: the name of the realtionship property or field of entity A; "_"' the name of the primary key column in table B. The foreign key column has the same type as primary key of table B and there is a unique key constraint on it.

My problem is that unique constraint on foreign key colum does not exists, so I'm wondering if something wrong with my code.

Here is my code:

First entity

@Entity
public class FootballPlayer {

    @Id
    private long id;

    @OneToOne
    private Ball ball;

    public FootballPlayer() {
    }

    public FootballPlayer(long id) {
        this.id = id;
    }

    public long getId() {
        return id;
    }

    public void setBall(Ball ball) {
        this.ball = ball;
    }

    public Ball getBall() {
        return ball;
    }
}

Second entity:

@Entity
public class Ball {

    @Id
    private long id;

    public Ball() {
    }

    public Ball(long id) {
        this.id = id;
    }

    public long getId() {
        return id;
    }
}

And here is scenario that should In my opinion ends with exception:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("pu");
EntityManager em = emf.createEntityManager();

FootballPlayer firstPlayer = new FootballPlayer(1L);
FootballPlayer secondPlayer = new FootballPlayer(2L);
Ball ball = new Ball(10L);

firstPlayer.setBall(ball);
secondPlayer.setBall(ball);

em.getTransaction().begin();
em.persist(ball);
em.persist(firstPlayer);
em.persist(secondPlayer);
em.getTransaction().commit();

em.close();
emf.close();

I'm using Hibernate 4.3.0, defined in pom.xml as follows:

<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-core</artifactId>
  <version>4.3.0.Final</version>
</dependency>
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-entitymanager</artifactId>
  <version>4.3.0.Final</version>
</dependency>

And in-memory database Derby 10.10.1.1:

<dependency>
  <groupId>org.apache.derby</groupId>
  <artifactId>derby</artifactId>
  <version>10.10.1.1</version>
</dependency>

persistence unit in persistence.xml:

<persistence-unit name="pu">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>

  <class>com.mprzybylak.minefields.jpa.relationships.onetoone.uni.Ball</class>
  <class>com.mprzybylak.minefields.jpa.relationships.onetoone.uni.FootballPlayer</class>

  <properties>
    <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
    <property name="javax.persistence.jdbc.url" value="jdbc:derby:memory:test;create=true" />
    <property name="javax.persistence.jdbc.user" value="APP" />
    <property name="javax.persistence.jdbc.password" value="APP" />             
    <property name="hibernate.show_sql" value="true" />
    <property name="hibernate.use_sql_comments" value="true"/>
    <property name="hibernate.hbm2ddl.auto" value="create" />
  </properties>

</persistence-unit>

I tried to switch to eclipselink, but I still have this problem. I used eclipselink 2.5.1

<dependency>
  <groupId>org.eclipse.persistence</groupId> 
  <artifactId>eclipselink</artifactId>
  <version>2.5.1</version>
</dependency>

With following configuration of persistence unit:

<persistence-unit name="pu" transaction-type="RESOURCE_LOCAL">

<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.mprzybylak.minefields.jpa.relationships.onetoone.uni.Ball</class>
<class>com.mprzybylak.minefields.jpa.relationships.onetoone.uni.FootballPlayer</class>

  <properties>
    <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
    <property name="javax.persistence.jdbc.url"value="jdbc:derby:memory:test;create=true" />
    <property name="javax.persistence.jdbc.user" value="APP" />
    <property name="javax.persistence.jdbc.password" value="APP" />

    <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
    <property name="eclipselink.logging.level.sql" value="FINE"/>
    <property name="eclipselink.logging.parameters" value="true"/>
  </properties>
</persistence-unit>

JPA is working in way that I think it should only when I put @JoinColumn(unique=true) annotation on ball field inside FootballPlayer class

So, am I doing something wrong in my code? Because it is hard to belive for me, that two major JPA providers do not follow JPA specification.

役に立ちましたか?

解決

What I think is that you discovered a bug, it both EclipseLink and Hibernate. I think, this part of the specification was simply ignored. So you should report the bug.

PS: this is also a requirement in JPA 2.0.

他のヒント

I can confirm this bug as well. I am using Derby DB with EclipseLink 2.0.0. Issue is there and I spend more than 3 hours trying to find what is wrong with my code... Obviously nothing.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top