Daimon
Daimon

Reputation: 375

JPA CascadeType Persist doesn't work with spring data

I have two entities, user:

@Data
@EqualsAndHashCode(exclude = "id")
@Entity
@Table(name = "users")
public class User {

    @Id
    @SequenceGenerator(name = "user_id_seq_gen", sequenceName = "users_id_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id_seq_gen")
    private long id;
    @Column(nullable = false, unique = true, length = 100)
    @NotNull
    @Length(min = 4, max = 100)
    private String email;
    @Column(nullable = false, length = 50)
    @NotNull
    @Length(min = 6, max = 100)
    private String password;

}

And verification:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Verification {

    @Id
    @Column(length = 20)
    private String code;

    @OneToOne(cascade = {CascadeType.PERSIST})
    private User user;

}

And I save these entities in this method:

@Transactional
    public void registerUser(User user) {
        user.setPassword(DigestUtils.md5Hex(user.getPassword()));
        String code = RandomStringUtils.random(20, true, true);
        Verification verification;
        while(true) {
            if (!verificationRepository.existsByCode(code)) {
                verification = new Verification(code, user);
                break;
            } else {
                code = RandomStringUtils.random(20, true, true);
            }
        }
        verificationRepository.save(verification);
    }

But CascadeType persist doesn't work, it throws the following exception:

org.postgresql.util.PSQLException: ERROR: null value in column "user_id" violates not-null constraint
  Подробности: Failing row contains (Oda2AolKrQXYSxuVmclO, null).

But when I change cascade type to MERGE, it works. And I don't understand why, because I create new User and new Verification at the same time. And first I need to save the user, then the verification. Do you know the answer?

Upvotes: 4

Views: 2180

Answers (1)

Jens Schauder
Jens Schauder

Reputation: 81907

Spring Data JPA uses the ID to determine if the instance is new or not. Since it seems you are setting the id to a non-null value Spring Data JPA considers it an existing entity and calls merge instead of persist.

Read "Saving Entities" in the Reference Documentation about how to tweak that behavior.

I recommend thinking in terms of Domain Driven Design and Aggregates/Aggregate Roots in order to determine the entities which should be linked via Cascade.ALL + DELETE_ORPHAN and those without any cascading and separate repositories instead.

I recommend reading "Advancing Enterprise DDD" about the topic.

Upvotes: 4

Related Questions