0

In my application a user places an order and sets the billing address to one of the address mapped with him. Now in future he edits that address.So my order will map to that updated address.

My Order entity

@Entity
public class Orders{
...

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

@OneToOne
private Address address;
...
}

Address entity

@Entity
@Table(name = "address")
public class Address {

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

private String address1;

...

}

Person entity

@Entity
public class Person{
...
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Address> addresses = new HashSet<>();
...
}

I want my Order entity to have a copy of the Address as it was during the creation of the order.Any changes in the Address by user in his profile, after order creation should have no impact on that Order.

Nadeem Haider
  • 160
  • 1
  • 12

1 Answers1

1

I assume you allow user to pick the address from his address list(Person#address), so when you submit your order it contains the address that is already on database, including the id that creates a relationship, does not create an record:

{
  user: {
    id: 10,
    email: "user@stackoverflow.com"
  },
  address: {
    id: 10,
    street: "5th Av"
  }
}

If you want to "have a copy of the Address" then you should first update your relationship in Order class like:

  @OneToOne(cascade = CascadeType.ALL)
  private Address address;

Then send the address without id, that would indicate your repository to create a new entry into database.

Json option:

{
  user: {
    id: 10,
    email: "user@stackoverflow.com"
  },
  address: {
    street: "5th Av", ...
  }
}

Or by removing the id on controller:

@PostMapping("/submit-order")
public Order submitOrder( @RequestBody Order order) {
  // Remove Order#id to detatch current record and enforce create a new one
  order.getAddress().setId(null);
  return this.orderRepository.save(order);
}

This way your order has an exclusive copy of address.

ERROR: org.springframework.orm.jpa.JpaSystemException with message "Address was altered from 1 to null"

If you receive this error is because you are removing the id of the entity within the scope of a transaction or session. You should create a copy of the entity out of that scope or use entity manager to detach the entity, here is a example.

@embeddable solution

Another solution would be to use an embeddable object instead, that way you can store the address fields on order table but have them as a composite object:

First you create an order address object with all required fields and mark it with @Embeddable annotation:

@Embeddable
public class AddressOrder {
  @Column("street")
  private String street;
  @Column("postal_code")
  private String po;
  @Column("city")
  private String city;
  @Column("country")
  private String country;

  // Getters and setters
}

Then you use the object on your order table as an attribute and mark it with @Embedded annotation.

@Entity
public class Orders {
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "user_id")
  private User user;

  @Embedded
  private AddressOrder address;

  // Getters and setters
}

You need to choose the solution according to the database approach you want to use.

Cristian Colorado
  • 2,022
  • 3
  • 19
  • 24
  • In your first solution if I set Address id to null then how will the Order point to any address. Moreover it also gives org.springframework.orm.jpa.JpaSystemException with message "Address was altered from 1 to null". @CristianColorado – Nadeem Haider Mar 10 '19 at 06:04
  • 1
    Please read the update i made to the answer, given new configuration when removing the id, you are asking to make a new entry on address and make a relationship to order. Order will have his copy, User will have his copy. As per the Exception, probably it is because you are using the entity within the scope of a transaction or session. You need to remove id outside of the transaction otherwise you need to use entity manager to detach the object, here is an example: https://stackoverflow.com/questions/26795436/spring-jparepository-detach-and-attach-entity/26812963 – Cristian Colorado Mar 10 '19 at 18:30
  • the Embeddable solution worked for me and thanks for explaining the doubt about the first approach. @CristianColorado – Nadeem Haider Mar 11 '19 at 05:57