休眠:如何保留与订单相关的信息

时间:2019-03-09 17:07:15

标签: java database hibernate jpa

在我的应用程序中,用户下订单并将账单地址设置为与他映射的地址之一。现在,他将来会编辑该地址。因此我的订单将映射到该更新的地址。

我的订单实体

@Entity
public class Orders{
...

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

@OneToOne
private Address address;
...
}

地址实体

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

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

private String address1;

...

}

人员实体

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

我希望我的Order实体拥有创建订单时的地址副本。创建订单后,用户在其个人资料中对Address的任何更改都不会对该订单产生影响。

1 个答案:

答案 0 :(得分:1)

我假设您允许用户从他的地址列表中选择地址(人#地址),因此,当您提交订单时,它包含数据库中已经存在的地址,包括创建关系的id,不会创建记录:

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

如果您想“ 拥有地址副本”,则应首先在Order类中更新您的关系,例如:

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

然后发送不带id的地址,这表明您的存储库将在数据库中创建一个新条目。

Json选项:

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

或通过删除控制器上的id

@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);
}

通过这种方式,您的订单具有唯一的地址副本。

错误:消息为“地址已从1更改为空”的org.springframework.orm.jpa.JpaSystemException

如果收到此错误,是因为要在事务或会话范围内删除实体的ID。您应该在该范围之外创建实体的副本,或者使用实体管理器来分离实体,这里是example

@嵌入式解决方案

另一种解决方案是改为使用可嵌入对象,这样您可以将地址字段存储在订单表上,但可以将它们作为复合对象:

首先,创建一个包含所有必填字段的订单地址对象,并用@Embeddable批注对其进行标记:

@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
}

然后,将订单表上的对象用作属性,并用@Embedded批注对其进行标记。

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

  @Embedded
  private AddressOrder address;

  // Getters and setters
}

您需要根据要使用的数据库方法选择解决方案。