【问题标题】:Hibernate: How do I persist order related informationHibernate:如何持久化订单相关信息
【发布时间】:2019-07-31 11:13:22
【问题描述】:

在我的应用程序中,用户下订单并将帐单地址设置为与他映射的地址之一。现在他将来会编辑那个地址。所以我的订单将映射到那个更新的地址。

我的订单实体

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

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

【问题讨论】:

  • 请提供您用于将订单插入数据库的代码

标签: java database hibernate jpa


【解决方案1】:

我假设您允许用户从他的地址列表中选择地址(Person#address),所以当您提交订单时,它包含已经在数据库中的地址,包括创建关系的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);
}

这样,您的订单就有了唯一的地址副本。

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

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

@embeddable 解决方案

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

首先你创建一个包含所有必填字段的订单地址对象,并用@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
}

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

【讨论】:

  • 在您的第一个解决方案中,如果我将 Address id 设置为 null,那么 Order 将如何指向任何地址。此外,它还为 org.springframework.orm.jpa.JpaSystemException 提供消息“地址已从 1 更改为空”。 @CristianColorado
  • 请阅读我对答案所做的更新,在删除 id 时给定新配置,您要求在地址上创建一个新条目并与订单建立关系。订单将拥有他的副本,用户将拥有他的副本。根据异常,可能是因为您在事务或会话范围内使用实体。您需要在事务之外删除 id 否则您需要使用实体管理器来分离对象,这里是一个示例:stackoverflow.com/questions/26795436/…
  • Embeddable 解决方案对我有用,感谢您解释对第一种方法的疑问。 @CristianColorado
猜你喜欢
  • 2022-10-21
  • 1970-01-01
  • 2019-01-20
  • 1970-01-01
  • 2018-04-07
  • 2015-07-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多