刷新 JPA 实体时出错
我有以下域模型
Currency ----< Price >---- Product
或者英文
产品有一个或多个价格。每个价格均以特定货币计价。
Price
有一个复合主键(由下面的 PricePK
表示),它由 Currency
和 Product
的外键组成>。 JPA 注释的 Java 类的相关部分如下(大部分省略了 getter 和 setter):
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Currency {
@Id
private Integer ix;
@Column
private String name;
@OneToMany(mappedBy = "pricePK.currency", cascade = CascadeType.ALL, orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
private Collection<Price> prices = new ArrayList<Price>();
}
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Product {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@OneToMany(mappedBy = "pricePK.product", cascade = CascadeType.ALL, orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
private Collection<Price> defaultPrices = new ArrayList<Price>();
}
@Embeddable
public class PricePK implements Serializable {
private Product product;
private Currency currency;
@ManyToOne(optional = false)
public Product getProduct() {
return product;
}
@ManyToOne(optional = false)
public Currency getCurrency() {
return currency;
}
}
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Price {
private PricePK pricePK = new PricePK();
private BigDecimal amount;
@Column(nullable = false)
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
@EmbeddedId
public PricePK getPricePK() {
return pricePK;
}
@Transient
public Product getProduct() {
return pricePK.getProduct();
}
public void setProduct(Product product) {
pricePK.setProduct(product);
}
@Transient
public Currency getCurrency() {
return pricePK.getCurrency();
}
public void setCurrency(Currency currency) {
pricePK.setCurrency(currency);
}
}
当我尝试 刷新 Product
的实例,我收到 StackOverflowError,所以我怀疑存在某种循环(或其他错误)在上面的映射中,有人能发现它吗?
I have the following domain model
Currency ----< Price >---- Product
Or in English
A Product has one or more Prices. Each Price is denominated in a particular Currency.
Price
has a composite primary key (represent by PricePK
below) which is composed of the foreign keys to Currency
and Product
. The relevant sections of the JPA-annotated Java classes are below (getters and setters mostly omitted):
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Currency {
@Id
private Integer ix;
@Column
private String name;
@OneToMany(mappedBy = "pricePK.currency", cascade = CascadeType.ALL, orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
private Collection<Price> prices = new ArrayList<Price>();
}
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Product {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@OneToMany(mappedBy = "pricePK.product", cascade = CascadeType.ALL, orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
private Collection<Price> defaultPrices = new ArrayList<Price>();
}
@Embeddable
public class PricePK implements Serializable {
private Product product;
private Currency currency;
@ManyToOne(optional = false)
public Product getProduct() {
return product;
}
@ManyToOne(optional = false)
public Currency getCurrency() {
return currency;
}
}
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Price {
private PricePK pricePK = new PricePK();
private BigDecimal amount;
@Column(nullable = false)
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
@EmbeddedId
public PricePK getPricePK() {
return pricePK;
}
@Transient
public Product getProduct() {
return pricePK.getProduct();
}
public void setProduct(Product product) {
pricePK.setProduct(product);
}
@Transient
public Currency getCurrency() {
return pricePK.getCurrency();
}
public void setCurrency(Currency currency) {
pricePK.setCurrency(currency);
}
}
When I try to refresh an instance of Product
, I get a StackOverflowError, so I suspect there's some kind of cycle (or other mistake) in the mapping above, can anyone spot it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我已经多次看到这个错误,但我不记得确切的解决方案。我的想法是,您需要从 PricePK(均为 @ManyToOne)中删除映射,并将其替换为 Price 上的 @AssociationOverrides。
请检查列名称是否正确,因为我看不到产品或货币上的 id 列。
I've seen this error a few times, but I can't remember the exact solution. I have the idea that you need to remove mapping from PricePK (both @ManyToOne) and replace that with @AssociationOverrides on Price.
please check that the column names are ok, as I can't see the id columns on Product or Currency.
我遇到了类似的问题,结果是由 OneToMany 注释中定义的 CascadeType.ALL 引起的。当您刷新产品时,它将尝试刷新持久上下文中的价格。
根据情况,在实体管理器中刷新产品时,您也许可以不刷新价格,例如:
I encountered a similar problem and it turned out to be caused by the CascadeType.ALL defined in the OneToMany annotation. When you refresh product, it is going to try to refresh the prices that are in the persistent context.
Depending on the situation, you may be able to get by without having the prices refreshed when the product is refreshed in the entity manager, such as:
难道您不应该直接在 Price 实体中将 Price 到 Product 和Currency 的关系声明为 ManyToOne ,并用 @IdClass(PricePK) 注释 Price 吗?
我不知道 Hibernate 如何处理这个问题,但我已经使用 OpenJPA 成功实现了这个问题。在这种情况下,PricePK 必须使用与 Price 中相同的名称来声明其字段,但使用简单类型(整数而不是货币或产品)。在 Price 中,您可能需要使用 @Id 注释产品和货币。请注意,这不符合 JPA 规范(@IdClass 仅支持简单字段)。
Shouldn't you just declare the relations from Price to Product and Currency as ManyToOne directly in the Price entity, and annotate Price with @IdClass(PricePK)?
I don't know how Hibernate handles this though, but I have successfully implemented this using OpenJPA. In that case, PricePK must declare its fields with the same names as in Price, but using the simple type instead (Integer instead of Currency or Product). In Price, you might need to annotate product and currency with @Id. Note that this is out of the JPA spec (@IdClass only supports simple fields).