@OneToMany与Composite键的关系

时间:2012-02-06 15:44:58

标签: hibernate jpa composite-key

我有以下模型(忽略不相关/明显的代码,如setter和getter):

@Entity
public class Invoice {
    @Id // sequence generated
    private Long invoiceId;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinColumn(name = "invoiceId", referencedColumnName = "invoiceId")
    @OrderBy("id.itemNumber")
    List<Item> items = new ArrayList<Item>();
}


@Entity
public class Item {
    @EmbeddedId
    private ItemPK id;
}


@Embeddable
public class ItemPK {
    private Long invoiceId;
    private Long itemNumber;
}

无法更改数据库结构,因为它是遗留数据库:(

itemNumber基本上是一个从零开始的索引。

如果我拿一个现有的Invoice并删除现有的项目并在列表中添加2个新项目,那么在尝试更新Invoice对象时会遇到各种各样的问题:

如果我将ItemPK保留为null,我会得到: org.hibernate.TransientObjectException:object是未保存的瞬态实例 - 在合并之前保存瞬态实例

如果我尝试自己填写ItemPK的值(发票和索引的ID),我会得到: org.hibernate.NonUniqueObjectException:具有相同标识符值的另一个对象已经关联使用会话 (数据库中已有一个发票项目,它有发票ID和索引= 0,就像我新项目列表中的第一个对象一样)。

如果我尝试将invoiceId保留为null(在ItemPK对象中),我得到: java.sql.BatchUpdateException:ORA-01400:无法插入NULL(“Item”。“invoiceId”)

有没有让Hibernate / JPA处理这个? 或者我是否需要完全删除关联,将列表定义为@Transient并填充它并将其保存在我的服务类中?

感谢。

1 个答案:

答案 0 :(得分:1)

这里实际上有一个双向关联,因为Item实体中的invoiceId实际上是Invoice的外键。因此,您应该将关联映射为双向关联,并使用@MapsId注释。它的javadoc有一个例子。