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 关系:外键未存储在多方表中的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot:与@JoinColumn 的 ManyToOne 关系保持外键为空

JPA 2.1 外键没有保存在 ManyToOne 级联上

springjpa定义引用类型

JPA映射关系

Spring Data JPA中的mappedBy

spring jpa ManyToMany 理解和使用