简体   繁体   中英

One-to-one mapping where primary key is foreign key - what annotations are required

I have the following tables:

Table: MyEntity {
    MyEntityId: primary-key, auto-generated
    // other fields ommited
}

Table: MyEntityLastAction {
    MyEntityId: primary-key
    // other fields ommited
}
  • MyEntityLastAction.MyEntityId has a constraint that it must exist in MyEntity . (This is a foreign key)
  • MyEntityLastAction is a VERY BIG record, hence why it is split out into another table

I am failing to setup the entity annotations correctly. Here is roughly where I am:

@Entity
public class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long myEntityId;
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    public MyEntityLastAction lastAction;
}

@Entity
public class MyEntityLastAction {
    @Id
    public long myEntityId;
    @OneToOne(mappedBy = "MyEntity", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "MyEntityId")
    public MyEntity myEntity;
}

I image trying to run the following:

MyEntity myEntity = new MyEntity();
myEntity.lastAction = new MyEntityLastAction();

em.save(myEntity);

I think you are looking for @MapsId annotation. This allows you to have @OneToOne with shared primary key.

See the below code for reference:

@Entity
class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long myEntityId;
    @OneToOne(mappedBy = "myEntity", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    public MyEntityLastAction lastAction;
}

@Entity
class MyEntityLastAction {
    @Id
    public long myEntityId;

    @OneToOne
    @JoinColumn(name="MyEntityId") 
    @MapsId     
    public MyEntity myEntity;
}

And to save the entity:

        MyEntity me = new MyEntity();
        me.lastAction = new MyEntityLastAction();
        me.lastAction.myEntity = me;
        entityManager.persist(me);

There are two issues: First, your mappedBy attribute should be the field name in MyEntity (in this case lastAction ). Second, since the mappedBy attribute indicates that the other side of the relationship handles how the two objects should be linked together, the join column annotation needs to be moved there. This should work:

@Entity
public class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long myEntityId;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @PrimaryKeyJoinColumn(name = "MyEntityId")
    public MyEntityLastAction lastAction;
}

@Entity
public class MyEntityLastAction {
    @Id
    public long myEntityId;

    @OneToOne(mappedBy = "lastAction", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    public MyEntity myEntity;
}

Note that if you're creating a new MyEntity with JPA, it won't cascade the new MyEntityLastAction within it. You'll have to first persist MyEntity , then set the ID in MyEntityLastAction to the one assigned to MyEntity , then persist MyEntityLastAction .

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