简体   繁体   中英

Hibernate class with primary key that is also a foreign key

@Entity
@Table(name = "USER_DATA")
public class UserData {
    Entity entity;

    @OneToOne(fetch = FetchType.EAGER)
    @PrimaryKeyJoinColumn(name="PK_FK_ENTITY")
    @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
    public Entity getEntity() {
        return entity;
    }

    public void setEntity(Entity entity) {
        this.entity = entity;
    }
}

Error given is "No identifier specified for entity". How can I specify that the entity field is both a primary and a foreign key? Note that there is no class hierarchy for 'UserData' here; it is just a single class. It just so happens that for every 'UserData' there will only be one 'Entity', hence we want to make it both a primary and a foreign key.

We have the same case in our application and it works with this (we annotate the properties not the getters, don't know if there is any difference):

public class UserData {
    @Id
    @Column(name="PK_FK_ENTITY")
    private int id;

    @OneToOne
    @JoinColumn(name="PK_FK_ENTITY")
    private Entity entity;
    ...

    public UserData (Entity entity, ...) {

        this.id = entity.getId();
        ...
    }
    ...
} 

Note that in the constructor you should set the id . Neither the id nor the entity should have a setter as it cannot change.

Also note that we don't use cascade in this case. We first save the Entity that has a generated id, and then UserData .

For one to one bidirectional mapping, just define the @MapsId annotation at the child entity.

@Entity
@Table(name = "USER_DATA")
public class UserData {

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "userData", orphanRemoval = true)
    private Entity entity;

    public void setEntity(Entity entity) {
        this.entity = entity;
        if (null != entity && entity.getUserData() != this) {
            entity.setUserData(this);
        }
    }
}

@Entity
@Table(name = "ENTITY")
public class Entity {

    @Id
    private Long id;

    @MapsId
    @OneToOne
    @JoinColumn(name = "user_data_id")
    private UserData userData;

    public void setUserData(UserData userData) {
        this.userData = userData;
        if (null != userData && userData.getEntity() != this) {
            userData.setEntity(this);
        }
    }

}

For one to many unidirectional mapping, You have to use @ElementalCollection and @CollectionTable and annotate Entity.class with @Embeddable annotation

        @Entity
        @Table(name = "USER_DATA")
        public class UserData {

             @ElementCollection
             @CollectionTable(name = "entity", 
                              joinColumns = @JoinColumn(name = "user_data_id"), 
                              uniqueConstraints = { @UniqueConstraint(columnNames     
= { "user_data_id", "name" }) })
             private final Set<Entity> entities = new LinkedHashSet<>();

             public void setEntities(Set<Entity> entities) {
                 this.entities.clear();
                 if (null != entities) {
                     this.entities.addAll(entities);
                 }
             }
        }

        @Embeddable
        public class Entity {

            @Column
            @Access(AccessType.FIELD)
            private String name;

        }

Kindly refers to the following articles for better understanding:
1. @OneToOne with shared primary key using @PrimaryKeyJoinColumn http://vard-lokkur.blogspot.my/2011/05/onetoone-with-shared-primary-key.html .

  1. @OneToOne with shared primary key using @MapsId http://vard-lokkur.blogspot.my/2014/05/onetoone-with-shared-primary-key.html

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