Hibernate实体循环引用生成StackOverflowError

时间:2014-11-14 14:37:01

标签: java hibernate

问题

我在尝试StackOverflowError引用Order和引用Product的{​​{1}}时获得Product。我知道这是由于有一个循环引用,但我不确定如何解决它。我是ORM的新手,但不是SQL / Schema Design的新手:通常,我会有Order表将Ordered_Products映射到Order,但我认为Hibernate会自动关注对我而言。

Product都有唯一的ID(这些ID是在应用程序外部生成的),因此没有两个Product是相同的。 Product ID也会在应用程序外部生成(我将在此管道中的早期流程中从CSV导入此数据)。

有人可以协助前进吗?

模型

Order.java

Order

Product.java

@Entity
@Table(name = "Orders")
class Order implements Serializable {

    private static final long serialVersionUID = 2916987431893884948L;

    @Id
    @Column(name="id")
    private Long id;

    @Column(name="contactName")
    private String contactName;

    @OneToMany(mappedBy = "order", fetch=FetchType.EAGER, cascade = CascadeType.ALL)
    private Set<Product> products;

    // ...plain old getters and setters omitted...

    public Set<Product> getProducts() {

        // Should this be done at the member variable declaration?
        if (null == products) {
            this.products = new HashSet<Product>();
        }

        return products;
    }

    public void addProduct(Product p) {
        p.setOrder(this);
        getProducts().add(p);
    }

    public String toString() { 
    /* plain old to String which prints all member vars */ 
    }
}

产生错误的代码

@Entity
@Table(name = "Products")
public class Product implements Serializable {

    private static final long serialVersionUID = 663408095532480033L;

    @Id
    @Column(name="id")
    private String id;

    @Column(name="size")
    private Size size;

    @OneToOne
    @JoinColumn(name="order_id", nullable=false)
    private Order order;

    // ...plain old getters and setters...

    public enum Size {
        EMPTY,
        XXSMALL,
        XSMALL,
        SMALL,
        MEDIUM,
        LARGE
    }

    public String toString() { 
    /* plain old to String which prints all member vars */ 
    }
}

堆栈跟踪

Product b = new Product();
b.setId("ABC123");
b.setSize(Product.Size.LARGE);

Product c = new Product();
c.setId("DEF456");
c.setSize(Product.Size.XSMALL);

Order o = new Order();
o.setId(551234L);
o.setContactName("Marco");
o.addProduct(b);
o.addProduct(c);
System.out.println("Order ID=" + o);

此处的问题是Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError at java.util.HashMap$KeyIterator.<init>(HashMap.java:1451) at java.util.HashMap$KeySet.iterator(HashMap.java:912) at java.util.HashSet.iterator(HashSet.java:172) at java.util.AbstractCollection.toString(AbstractCollection.java:454) at java.lang.String.valueOf(String.java:2979) at java.lang.StringBuilder.append(StringBuilder.java:131) at com.code4armour.shippingtracker.ui.model.Order.toString(Order.java:207) at java.lang.String.valueOf(String.java:2979) at java.lang.StringBuilder.append(StringBuilder.java:131) at com.code4armour.shippingtracker.ui.model.Band.toString(Band.java:78) at java.lang.String.valueOf(String.java:2979) at java.lang.StringBuilder.append(StringBuilder.java:131) at java.util.AbstractCollection.toString(AbstractCollection.java:462) at java.lang.String.valueOf(String.java:2979) at java.lang.StringBuilder.append(StringBuilder.java:131) at com.code4armour.shippingtracker.ui.model.Order.toString(Order.java:207) at java.lang.String.valueOf(String.java:2979) at java.lang.StringBuilder.append(StringBuilder.java:131) at com.code4armour.shippingtracker.ui.model.Band.toString(Band.java:78) 调用Order.toString(),反之亦然

2 个答案:

答案 0 :(得分:2)

  

这里的问题是调用Product.toString()的Order.toString(),反之亦然

您已经确定了问题,很清楚为什么要获得StackOverflowError。只是不要从另一个实体的toString()调用一个实体toString()

答案 1 :(得分:1)

您可能需要考虑包含两者实例的管理类/对象。通过这个,您可以单独安全地调用两个toString()方法。

修改(从我的第一条评论继续):

Order_Product_Link(table)

  • OrderID(FK)
  • ProductID(FK)

约束: - orderID和productID的组合应该是唯一的

考虑:

  • 确保级联删除。因此,如果删除产品条目,则需要删除引用其ID的Order_Product_Link中的所有条目。但是,您很可能不希望删除该订单。反之亦然。