2

I'm writing a simple Order-Payment one-to-one association:

Order class relevant code:

@Entity
public class Order implements Serializable {

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

    (...)   

    @OneToOne(cascade=CascadeType.ALL, mappedBy="order")
    private Payment payment;

Payment class relevant code:

@Entity
public class Payment implements Serializable {

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

    @OneToOne
    @MapsId 
    private Order order;

Then I want to implement a basic method to seed my test database using Spring Data JPA repositories, but if I try the following code, I get a PersistentObjectException saying detached entity passed to persist:

Order o1 = new Order(null, Instant.parse("2019-06-20T19:53:07Z"));
orderRepository.save(o1);
Payment p1 = new Payment(null, Instant.parse("2019-06-23T13:02:55Z"), o1);
paymentRepository.save(p1);

Same problem happens if I try this way:

Order o1 = new Order(null, Instant.parse("2019-06-20T19:53:07Z"));
Payment p1 = new Payment(null, Instant.parse("2019-06-23T13:02:55Z"), o1);
orderRepository.save(o1);
paymentRepository.save(p1);

The only way it worked was as follows:

Order o1 = new Order(null, Instant.parse("2019-06-20T19:53:07Z"));
Payment p1 = new Payment(null, Instant.parse("2019-06-23T13:02:55Z"), o1);
o1.setPayment(p1);
orderRepository.save(o1);
paymentRepository.save(p1);

I'd like to understand why only the last approach works. In a many-to-one association I don't have to set that two-way association before saving in order to work. What am I missing about detached entities behavior this case? Thanks.

Sana
  • 360
  • 3
  • 13
Nelio Alves
  • 1,231
  • 13
  • 34

2 Answers2

2

Because we have to set the Child Entity for Parent Entity as you have done using o1.setPayment(p1);

No need to pass the id as null as it will be @GeneratedValue. You may have to create an appropriate constructor for them.

As you are using cascade=CascadeType.ALL you may save the Parent and Child as below no need use save() for both entity

//save Parent-Child at same 
        @PostMapping(value = "/onetoone")
        public String OneToOne(@RequestBody ParentOne parent)
        {
            ChildOne childOne = parent.getChildOne();
            childOne.setParentOne(parent);
            parent.setChildOne(childOne);
            parentOneRepository.save(parent);
            return "saved";

            /*{
                "parentName":"Parent Name",
                "childOne":{
                    "childName":"Child Name"
                }
            }*/
        }

Discussion

Romil Patel
  • 12,879
  • 7
  • 47
  • 76
0

Try this one,

Order o1 = new Order(null, Instant.parse("2019-06-20T19:53:07Z"));
Payment p1 = new Payment(null, Instant.parse("2019-06-23T13:02:55Z"), o1);
o1.setPayment(p1);
orderRepository.save(o1);

No need the save method for Payment. Because you used the cascade type like @OneToOne(cascade=CascadeType.ALL, mappedBy="order") Whenever you save the Order then Payment also saved.

Sana
  • 360
  • 3
  • 13