1

I am trying to understand the JPA Spring Boot implementation for One-to-One mapping classes and was hoping if anyone could provide me a clear picture.

  1. One to One mapping Scenario: Table foo and Table childfoo Foo has the columns foo_id,foo_name, foo_place childfoo has the columnd foo_id(foreignkey of foo table), childfoo_name

Here is the JPA entity implementation I've made so far:

@Entity
@Data
@Table(name = "foo")
public class foo implements Serializable {

/**
 * 
 */
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "foo_id")
private Integer fooId;

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name="fooId")
private ChildFoo childFoo;
}

ChildFoo class

@Entity
@Data
@NoArgsConstructor
@EqualsAndHashCode(exclude ="foo")
@Table(name = "childfoo")
public class Childfoo implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -8142203085486540150L;
    
    @Id
    private Integer fooId;

    @OneToOne(cascade = CascadeType.ALL, optional = false, fetch = FetchType.LAZY)
    @PrimaryKeyJoinColumn(name = "foo_id", referencedColumnName = "fooId")
    private Foo foo;
    
    @Column(name="child_name")
     private String childName;

   }

I've created a repository for the Foo and I am using FooRepository.save(foo) in the controller to save the data.

Controller code to add the foo and childfoo:

Foo foo = new Foo();
foo.set...

   ChildFoo childFoo = new ChildFoo();
        childFoo.setChildName("abc");
        childFoo.setFoo(foo);

foo.setChildFoo(childFoo);
fooRepository.save(foo);


 

But I am getting the error:

ids for this class must be manually assigned before calling save().

user6090970
  • 185
  • 1
  • 3
  • 14
  • `fooId` on `Childfoo` doesn't have an ID generator strategy specified, so you'll have to set it manually. – Philip Wrage May 11 '21 at 01:56
  • But it is supposed to be the foreign key...which is the primary key of the foo i.e. foo_id. Is there a way I can specify this in the code? – user6090970 May 11 '21 at 02:10
  • 1
    Then what will be the Id for `Childfoo`? You've already specified the foreign key relationship to `Foo` from `Childfoo` with the annotations on the `private Foo foo` field. – Philip Wrage May 11 '21 at 02:14
  • There is no id field in childfoo....i.e. the only unique id is the id of foo in the childfoo table – user6090970 May 11 '21 at 02:42
  • According to your example code, within `Childfoo` you have annotated `fooId` with `@Id`, making it the ID of `Childfoo`. – Philip Wrage May 11 '21 at 03:25
  • Exactly...but I am still getting that error message.. Should I save the foo first (which will generate the fooID) then save the childfoo?(I'll need to create a childfoo repository for this) – user6090970 May 11 '21 at 03:48

1 Answers1

2

From your comments it appears you are trying to use a shared primary key strategy where ChildFoo will also use fooId as its own primary key.

If that's the case, then I think you need to update some of your JPA annotations:

@Entity
@Data
@Table(name = "foo")
public class Foo implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "foo_id")
    private Integer fooId;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "foo")
    private ChildFoo childFoo;

}


@Entity
@Data
@NoArgsConstructor
@EqualsAndHashCode(exclude ="foo")
@Table(name = "childfoo")
public class ChildFoo implements Serializable {

    private static final long serialVersionUID = -8142203085486540150L;
    
    @Id
    @Column(name = "foo_id")
    private Integer fooId;

    @OneToOne(cascade = CascadeType.ALL, optional = false)
    @MapsId // primary key copied from Foo
    @JoinColumn(name = "foo_id")
    private Foo foo;
    
    @Column(name="child_name")
     private String childName;

}

And you may need save the instance of Foo (thereby generating the shared Id) before associating and saving the ChildFoo, but I don't think that's necessary once everything is properly annotated.

Speaking of annotations, I only removed the lazy fetch type from your original annotations to clarify updates. You should be able to include them without any issues.

Additional useful links: Shared primary key with JPA and Spring Boot OneToOne shared primary key - JPA2.0 updates

Philip Wrage
  • 1,505
  • 1
  • 12
  • 23