zvzvzxvzxv
zvzvzxvzxv

Reputation: 117

Using @PrimaryKeyJoinColumn annotation in spring data jpa

I try to use the @PrimaryKeyJoinColumn annotation. When doing this, I get an error - attempted to assign id from null one-to-one property.

The user is saved, but the address is not saved. I want to create a common primary key for the User and Address table. I found an example here.

Please, tell me what I'm doing wrong, why doesn't this example work for me?

https://github.com/mytestPercon/TestHiber

User.java

@Entity
@Table(name = "user", schema = "TestKeyJoin")
public class User implements Serializable {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "id")
   private Long id;

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

   @OneToOne(mappedBy = "user")
   @PrimaryKeyJoinColumn
   private Address activated;

   // Getter and Setter ...
}

Address.java

@Entity
@Table(name = "Address", schema = "TestKeyJoin")
public class Address implements Serializable {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "id")
   private long id;

   @Basic
   @Column(name = "city")
   private String city;

   @OneToOne
   @MapsId
   @JoinColumn(name = "id")
   private User user;

   // Getter and Setter ...

}

SaveController.java

@Controller
public class SaveController {

   @Autowired
   ServiceJpa serviceJpa;

   @GetMapping(value = "/saveUser")
   public String getJpa () {
      User user = new User();
      user.setId(1L);
      user.setName("Michael Joseph Jackson");
      serviceJpa.saveUser(user);

      Address address = new Address();
      address.setId(1L);
      address.setCity("Los Angeles");
      serviceJpa.saveActivated(address);

      return "/saveUser";
   }
}

Upvotes: 1

Views: 5991

Answers (2)

SternK
SternK

Reputation: 13111

Try to correct your mapping in the following way:

@Entity
@Table(name = "user", schema = "TestKeyJoin")
public class User implements Serializable {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "id")
   private Long id;

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

   @OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
   private Address address;

   // ...
}

@Entity
@Table(name = "Address", schema = "TestKeyJoin")
public class Address implements Serializable {

   @Id
   private Long id;

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

   /* You can use @PrimaryKeyJoinColumn instead of the @MapsId here.
      See the Example 153. Derived identifier @PrimaryKeyJoinColumn
      from the hibernate documentation.
   */
   @OneToOne
   @MapsId
   @JoinColumn(name = "id")
   private User user;

   // ...
}

and then save user in the following way:

@GetMapping(value = "/saveUser")
public String getJpa () {

   User user = new User();
   user.setName("Michael Joseph Jackson");

   Address address = new Address();
   address.setCity("Los Angeles");

   // make both sides of the bidirectional @OneToOne in-sync
   user.setAddress(address);
   address.setUser(user);

   serviceJpa.saveUser(user);

   return "/saveUser";
}

And several notes:

  1. Whenever a bidirectional association is formed, the application developer must make sure both sides are in-sync at all times.

  2. You should not save your entities separately, you just should use a proper cascading on your association.

  3. You should not set value for the generated identifier.

  4. When you use @MapsId on the Address.user, it actually means that the Address entity will borrow the identifier from the one-to-one association. So, you should not use @GeneratedValue annotation for the Address.id. (See this)

Upvotes: 6

Surya mdl
Surya mdl

Reputation: 89

Remove the @GeneratedValue(strategy = GenerationType.IDENTITY) on id field in address entity as it is a foreign key of user entity, it should not be auto incremented. EDIT:Try by adding these lines

 public String getJpa () {

            User user = new User();
            user.setId(1L);
            user.setName("Michael Joseph Jackson");
            Address address = new Address();
            address.setId(1L);
            address.setCity("Los Angeles");
            user.setActivated(address);
            serviceJpa.saveUser(user);
             return "/saveUser";
        }

Upvotes: -1

Related Questions