JPA ManyToOne 关系:外键未存储在多方表中
Posted
技术标签:
【中文标题】JPA ManyToOne 关系:外键未存储在多方表中【英文标题】:JPA ManyToOne Relationship: foreign key not being stored in table of many side 【发布时间】:2016-06-13 17:39:23 【问题描述】:OneToMany 关系的从属方:
@Entity
@Table(name="xxx_customer")
@XmlRootElement(name="Customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer implements Serializable
@OneToMany(cascade=CascadeType.ALL, mappedBy="customer")
private List<CreditCard> creditCards;
public void addCreditCart(CreditCard creditCard)
creditCards.add(creditCard);
ManyToOne 关系的拥有方:
@Entity
@Table(name="xxx_credit_card")
@XmlRootElement(name="CreditCard")
@XmlAccessorType(XmlAccessType.FIELD)
public class CreditCard implements Serializable
@ManyToOne(optional=false)
@JoinColumn(name="customer_id", referencedColumnName="id")
private Customer customer;
从 OrderManager 调用以创建客户和信用卡记录:
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class OrderManager
@Inject
@UserDatabase
private EntityManager em;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void placeOrder(ShoppingCart cart)
try
Customer customer = cart.getCustomer();
customer.addCreditCart(cart.getCreditCard());
em.persist(customer);
catch(Exception ex)
ctx.setRollbackOnly();
MessageUtil.addMessage(FacesMessage.SEVERITY_ERROR,
"Place Order", "Error placing order!");
ex.printStackTrace();
在两个表中都创建了数据,但 CreditCard 表的 customer_id 字段为空。它不包含预期的客户记录的 id。
【问题讨论】:
代码显示您向客户添加信用卡,但正如您所提到的,这种关系从属于 CreditCard->Customer 关系。你是在设置信用卡的客户吗?没有它,就不会设置外键。 我在 Order 和 Customer 之间使用相同类型的关系,其中 Order 是拥有方。 Order 表中的 customer_id 列按预期填充 除非您将客户添加到订单中,否则不会。可能在您的 customer.addOrder 方法中,您既将订单添加到集合中,又将“此”客户添加到订单中。 JPA 将实体视为 POJO,不会为您进行关系维护。 JPA 确实维护了这种关系,以免我不得不编写代码:em.persist(customer); creditCard.setCustomerId(customer.getId()); em.persist(信用卡);但是这个缩写版本总是使用两个表的主键和被填充的外键:customer.setCreditCard(creditCard) em.persist(customer);您正在做的事情是,我正在尝试建立双向关系,也许,正如您所说,它不像我认为的那样有效。我将不得不探索这种思路。 您的 cmets 不正确。按照上面的建议将客户设置在信用卡上,它会起作用。 【参考方案1】:为了建立双向关系,您必须确保一侧的更新也会更新另一侧。它可以通过像这样的“add”或“set”方法来解决:
您要么修改 Customer 类(建议的解决方案,因为您在管理器代码中使用 add 方法):
@Entity
@Table(name="xxx_customer")
@XmlRootElement(name="Customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer implements Serializable
@OneToMany(cascade=CascadeType.ALL, mappedBy="customer")
private List<CreditCard> creditCards;
public void addCreditCart(CreditCard creditCard)
if(creditCard.getCustomer()!=this) creditCard.setCustomer(this);
creditCards.add(creditCard);
或者像这样修改 CreditCard 类:
@Entity
@Table(name="xxx_credit_card")
@XmlRootElement(name="CreditCard")
@XmlAccessorType(XmlAccessType.FIELD)
public class CreditCard implements Serializable
@ManyToOne(optional=false)
@JoinColumn(name="customer_id", referencedColumnName="id")
private Customer customer;
public setCustomer(Customer customer)
if(!customer.getCreditCards().contains(this)) customer.getCreditCards().add(this);
this.customer=customer;
现在,每次您更新 CreditCard 实例中的客户字段时,您都会在另一侧更新信用卡列表,反之亦然。 您可以修改这两个类,但必须确保不会出现无限循环。
【讨论】:
以上是关于JPA ManyToOne 关系:外键未存储在多方表中的主要内容,如果未能解决你的问题,请参考以下文章