How to persist oneToOne relation when saving secondary Entity

Viewed 297

I'm using SPRING DATA JPA and I have following entities:

public class EntityA {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SOME_SEQ")
    @SequenceGenerator(sequenceName = "SOME_SEQ", allocationSize = 1, name = "SOME_SEQ")
    private Long id;

    private String name;
    
    @OneToOne(mappedBy = "entityBField", cascade = CascadeType.ALL)
    private EntityB entityB;
}
    
    
public class EntityB {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SOME_OTHER_SEQ")
    @SequenceGenerator(sequenceName = "SOME_OTHER_SEQ", allocationSize = 1, name = "SOME_OTHER_SEQ")
    private Long id;

    private Integer type;

    @OneToOne
    @JoinColumn(name = "entityaId", referencedColumnName = "id")
    private EntityA entityBField;
}

This is the tables definition:

create table EntityA(
  id int primary key,
  name varchar(255)
);
create table EntityB(
  id int primary key,
  type int,
  entitya_Id int  FOREIGN KEY ("entitya_Id")
      REFERENCES "EntityA" ("id")
);

I create and save one instance as follow:

    EntityA a = new EntityA();
    EntityB b = new EntityB();
    a.setEntityB(b);
    entityARepository.save(a)

What happens is that both entityA and entityB are persisted, but the foreign key entityaId on EntityB is null. Could you suggest how should I persist the foreign key linking EntityB to EntityA?

2 Answers

You need to implement method EntityA.setEntityB like this:

public class EntityA {

    public void setEntityB(EntityB entityB) {
        if (entityB == null) {
            if (this.entityB != null) {
                this.entityB.setEntityBField(null);
            }
        }
        else {
            entityB.setEntityBField(this);
        }
        this.entityB = entityB;
    }

}

EntityB.setEntityBField should be usual setter:

public class EntityB {

  public void setEntityBField(EntityA entityBField) {
    this.entityBField = entityBField;
  }

}

Also, you might need "optional = false" in the annotation:

@OneToOne(mappedBy = "entityBField", cascade = CascadeType.ALL, optional = false)
private EntityB entityB;

See the example in this article: https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/

Note:

mappedBy = "entityBField" means that

EntityB.entityBField is responsible for managing one-to-one relationship,

so when you create EntityB b = new EntityB() and set a.setEntityB(b), then b.entityBField is null when you do cascading save: entityARepository.save(a)

This is why b.entityBField (foreign key "entitya_Id") is null in the database.

By implementing correct setter in EntityA, you help JPA understand, that entityB.entityBField should be set to the primary key of EntityA (entityB.setEntityBField(this))

The easiest solution would be like this:

EntityA a = new EntityA();
EntityB b = new EntityB();
b.setEntityBField(a);
entityARepository.save(a)

The only change you need to make is the following line:

b.setEntityBField(a);
Related