I have table User entity/table with id as primary key / string / uuid generated value. I also have UserDetails entity/table with userId as primary key / string / foreign key to user.id. Note that in the UserDetails java entity I don't need the User entity, but user_id is enough.
I'm trying to define the entities in a way that inserting new User entity will also create a new UserDetails row, with the same id.
Any ideas how to implement this?
To clarify, what I want can be achieved in sql by doing this:
BEGIN
INSERT INTO user (id, name) VALUES ('auto-generated-uuid-31212', 'Bobby');
INSERT INTO user_details (user_id) VALUES ('auto-generated-uuid-31212');
COMMIT
My last attempt was to have 2 columns on UserDetails - String userId with @Id (no other mapping), and User user with OneToOne/JoinColumn(name="userId")/MapsId annotations.
However it seems like spring/hibernate attempts to then save the UserDetails info first rather than together with the User, and I end up getting foreign key constraint fails on the foreign key constraint.
Quick code:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Entity
public class User {
@Id
@Column
@GeneratedValue(strategy = GenerationType.UUID)
private String id;
@Column
private String name;
@JoinColumn(name = "id")
@OneToOne(cascade = CascadeType.ALL)
@NotNull
@Builder.Default
private UserDetails userDetails = new UserDetails();
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Entity
public class UserDetails {
@Id
private String userId;
@OneToOne
@JoinColumn(name = "userId")
@MapsId
private User user;
}
Edit: I forgot to add the UserDetails property on the User to this question.
I finally got it working. Since you have two tables you will need at least two inserts. Another option is to embed the user details (@Embeddable instead of @Entity on UserDetails and some other changes) but this requires the columns in the user-table. Then you have only one table and can go with a single insert.
public class User {
...
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private UserDetails details;
public User(String name)
{
userDetails = new UserDetails(this);
this.name = name;
}
}
with UserDetails:
public class UserDetails {
@Id
@Column(name = "user_id")
private String userId;
@OneToOne
@MapsId
@JoinColumn(name = "user_id")
private User user;
public UserDetails(User user)
{
this.user = user;
}
}
Now if you create a user the details are automatically created too and will be persisted to the database along with the user.