Skip to content
Advertisement

JPA cascade actions on one-to-one relationship

I have the following question regarding one to one relationships (and I guess one to many also):

Let’s suppose I have the following tables:

create table user (
    id bigint auto_increment primary key,
    username varchar(100) not null,
    constraint UK_username unique (username)
);
create table user_details(
    userId bigint not null primary key,
    firstName varchar(100) null,
    lastName  varchar(100) null,
    constraint user_details_user_id_fk foreign key (userId) references user (id)
);

As you can see the two tables share the same primary key. Now the entities I created are the following:

import lombok.Data;

import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

@Data
@Entity
public class User {

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

    @NotBlank
    @Column(unique = true)
    @Size(min = 1, max = 100)
    private String username;

    @MapsId
    //without this I get an exception on this table not having a column named: userDetails_userId
    @JoinColumn(name = "id")
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private UserDetails userDetails;
}
import lombok.Data;

import javax.persistence.*;
import javax.validation.constraints.Size;

@Data
@Entity(name = "user_details")
public class UserDetails {

    @Id
    private Long userId;

    @Column(unique = true)
    @Size(min = 1, max = 100)
    private String firstName;

    @Column(unique = true)
    @Size(min = 1, max = 100)
    private String lastName;

}

When I try to persist a new user I have a user object with all the values generated except of the user.id and the userDetail.userId. When I try to persist this the error I get is the following:

"org.springframework.orm.jpa.JpaSystemException: ids for this class must be manually assigned before calling save(): com.app.entity.UserDetails; nested exception is org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.app.UserDetails

Note that to save a User entity I created this interface:

public interface UserRepository extends JpaRepository<User, Long> { }

and I use the save method provided.

    ...

    @Autowired
    private UserRepository userRepository;

    ...

    public ResponseEntity<HttpStatus> addUser(User user) {
        userRepository.save(user);
        return ResponseEntity.ok(HttpStatus.OK);
    }

the object before saving looks like this:

User(id=null, username=test, userDetails=UserDetails(userId=null, firstName=test, lastName=test))

I was wondering if I can simply save a user object and cascade the generated key to the userDetail.

Should I use another approach for saving or there is something wrong with my entities?

Advertisement

Answer

You’ve done things from the wrong direction.

@Data
@Entity
public class User {

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

    @NotBlank
    @Column(unique = true)
    @Size(min = 1, max = 100)
    private String username;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
    private UserDetails userDetails;
}

@Data
@Entity(name = "user_details")
public class UserDetails {

    @Id
    private Long userId;

    @Column(unique = true)
    @Size(min = 1, max = 100)
    private String firstName;

    @Column(unique = true)
    @Size(min = 1, max = 100)
    private String lastName;

    @MapsId
    @JoinColumn(name = "USERID")
    @OneToOne(fetch = FetchType.LAZY)
    private User user;
}

With this, you can just set the userDetail.user reference and JPA will persist both the user, assign it a ID and use that to populate the UserDetail.id value for you – in your model and in the database.

You should maintain the user.userDetail reference, but it is less consequential to the database row data and more for object consistency reasons.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement