Say I have a unidirectional @ManyToOne relationship like the following:
@Entity
@Table(name = "TestUser")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class TestUser {
@Id
@Column(nullable = false)
private String id;
@Column(name = "some_property")
private String someProperty;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TestUser)) return false;
return id != null && id.equals(((TestUser) o).getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
}
@Entity
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class BugTicket {
@Id
@GeneratedValue
@Column(name = "id", nullable = false)
private Long id;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn
private TestUser testUser;
public BugTicket(TestUser testUser) {
this.testUser = testUser;
}
}
class Driver {
public void run(String... args) throws Exception {
TestUser u1 = new TestUser("user-id-1", "value1");
userRepository.save(u1);
var ticket = new BugTicket(u1);
ticketRepository.save(ticket);
ticket.getTestUser().setSomeProperty("value2");
ticketRepository.save(ticket);
}
}
I want to update the user entity's 'someProperty' whenever I update BugTicket entity. Hence I added CascadeType.ALL to BugTicket's user.
However, when save is called, hibernate tries to create a new user and throws exception
Hibernate: insert into test_user (some_property, id) values (?, ?)
2022-10-02 18:33:39.404 WARN 30632 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 23505
2022-10-02 18:33:39.405 ERROR 30632 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: duplicate key value violates unique constraint "test_user_pkey"
Detail: Key (id)=(user-id-1) already exists.
Why does hibernate try to insert User once again? Is removing CascadeType.all from BugTicket, and explicitely saving user ' ticket.getTestUser().setSomeProperty("value2");' the only way?
CodePudding user response:
When you save an entity with jparepository it returns the persisted user so you need to use that
CodePudding user response:
When you try to save your "ticket", ticket.getTestUser() is detached so Hibernate will try to create it. You need to work inside a transaction.