简体   繁体   中英

JPA fetching value from Many to One relationship

I have a problem embedding a single value from many-to-one relationship in JPA. Below there's some code that I use to init a test schema as well as my test entities.

The idea is that there's a table EMPLOYEE that has a reference to table RANK. Table RANK in turn contains the name of the RANK. Each employee refers to its rank.

When I try to run my code I got the following exception:

Caused by: org.hibernate.AnnotationException: SecondaryTable JoinColumn cannot reference a non primary key
    at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:623)
    at org.hibernate.cfg.annotations.EntityBinder.bindJoinToPersistentClass(EntityBinder.java:764)
    at org.hibernate.cfg.annotations.EntityBinder.createPrimaryColumnsToSecondaryTable(EntityBinder.java:756)
    at org.hibernate.cfg.annotations.EntityBinder.finalSecondaryTableBinding(EntityBinder.java:684)
    at org.hibernate.cfg.SecondaryTableSecondPass.doSecondPass(SecondaryTableSecondPass.java:29)

Here is a DB schema

CREATE TABLE RANK (
    ID INT NOT NULL, 
    NAME VARCHAR
);
ALTER TABLE RANK ADD PRIMARY KEY (ID);
INSERT INTO RANK (ID, NAME) VALUES (1, 'WORKER')

CREATE TABLE EMPLOYEE(
    ID INT NOT NULL, 
    NAME VARCHAR,
    RANK_ID INT NOT NULL
);
ALTER TABLE EMPLOYEE ADD PRIMARY KEY (ID);
INSERT INTO EMPLOYEE (ID, NAME, RANK_ID) VALUES (1, 'Bobby', 1);

And finally, the only entity:

@Entity
@Table(name = "EMPLOYEE")
@SecondaryTable(name = "RANK", pkJoinColumns=@PrimaryKeyJoinColumn(name="ID", referencedColumnName = "RANK_ID"))
public class Employee {

    @Id
    @Column(name = "id")
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    private int id;

    @Column(name = "NAME")
    private String name;

    @Column(name = "RANK_ID")
    private int rankId;

    @Column(name = "name", table = "RANK")
    private String rank;

    public Employee() {

    }
}

I'd be grateful for any hints on how to solve this case. Looks quite common to assume that this is not possible with JPA.

Reference the Employee ID when using the secondary table annotation and remove the rank_id . You are saying that the data is spread across multiple tables by using that annotation so basically the primary key of both is the same. And actually since both PK have the same identifier, it shouldn't even be necessary to define the @PrimaryKeyJoinColumn .

Please refer here: https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/SecondaryTable.html

On the other hand if you just want a Many To One relationship you can use the @ManyToOne annotation and @JoinColumn in the rank_id .

If you read this section of the Java Persistence Wikibook you will see that what you are wanting is not covered by the JPA spec and therefore may not be supported by the underlying provider:

The JPA spec does not cover this directly, so if you have this scenario the first thing to consider, if you have the flexibility, is to change your data model to stay within the confines of the spec.

@SecondaryTable is primarily designed to link one-to-one tables into one Entity.

The 'standard' way to achieve what you you want is to create a separate Entity for Rank and EAGER fetch it in Employee . You could then have a method in Employee called getRankName() which returns this.rank.getName() . Thus, your Employee class would look like this:

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id
    @Column(name = "id")
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    private int id;

    @Column(name = "NAME")
    private String name;

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "RANK_ID", referencedColumnName = "ID")
    private Rank rank;

    public Employee() {

    }

    public String getRankName() {
        if (this.rank == null) {
            return null;
        }
        return this.rank.getName();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM