I have some codes , but it gets a error at personRepository.save(person2) , no need to fix this but just explaining for me why this throws : detached entity passed to persist.
@Entity
public class Person {
@Id
@GeneratedValue
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "wallet_id", insertable = false, updatable = false)
private Long wallet_id;
@ManyToOne (fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "wallet_id",referencedColumnName = "id", insertable = true, updatable = true )
private Wallet wallet;
}
public void testSave(String name) {
Wallet walletNewNoHaveInDB = new Wallet(); // Generated id.
Person person = new Person(); // Generated id.
person.setName(name);
person.setWallet(walletNewNoHaveInDB);
personRepository.save(person); // This is OK and inserted into DB both(wallet , person).
Person person2 = new Person(); // Generated id.
person2.setName(name);
person2.setWallet(walletNewNoHaveInDB);
personRepository.save(person2); /// detached entity passed to persist
}
I understand you did not annotate your test with @Transactional - in that case scenario spring is creating transaction for you to perform the "save" as you call it. More on that here: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
In 1st case you are having "new" objects (without ID, and unmanaged by JPA provider), and you did specify cascading so JPA provider knows how to save it in 1 transaction.
In 2nd case, you are adding wallet that is already managed object, but without transaction.
You either need to do it all in @Transactional scope (annotate your test), or if you pass object from "outside" of transaction (that's yr scenario), again...you need to have a transaction - so you need to start it and call merge() on the object that comes from outside of it.