我正在使用Play框架编写一个应用程序,它使用JPA注释和Hibernate作为所包含的Ebean ORM持久层的一部分。我在弄清楚与外键相关的JPA注释时遇到了一些麻烦。在我的MySQL数据库中,有一个名为Locations的主表存储地址(街道,城市,州,邮政等)。数据库中的许多其他表以一对一或多对多关系使用此表。问题是,当我尝试将多个字段映射到位置中的id字段时出现错误。
例如,Docks和LineItems是两个包含对Location的引用的模型。每个Dock都有一个Location,每个LineItem有两个Locations:origin和destination。
所以,在Dock中,我有代码:
@OneToOne(optional=false)
@JoinColumn(name="loc_id")
public Location location;
在LineItem中,我有:
@OneToOne(optional=false)
@JoinColumn(name="origin")
public Location origin;
@OneToOne(optional=false)
@JoinColumn(name="destination")
public Location destination;
但是我无法将它们全部映射到Locations中的id字段,因为JPA不允许我这样做:
@Id
@GeneratedValue
@OneToOne(mappedBy="location", fetch=FetchType.EAGER)
@OneToOne(mappedBy="origin", fetch=FetchType.EAGER)
@OneToOne(mappedBy="destination", fetch=FetchType.EAGER)
@Column(name="loc_id")
public Long id;
我有一种感觉,我只是以错误的方式解决这个问题。是否有更简单的方法在JPA中拥有外键约束?我真的不想在我的表中创建一堆额外的列,因为Locations确实被引用了很多。任何建议我直截了当都会受到赞赏。
答案 0 :(得分:0)
您显示的位置配置没有任何意义。如果可以用你的全部意图解释它对JPA意味着什么:
显然这没有任何意义,对吧?如果您要在位置中拥有所有这些@OneToOne
注释,则每个注释都需要位于其自己的字段上:一个Dock和两个LineItem,以及您提到的所有其他位置关系的更多内容。这显然是不可取的,因为位置只是那个,并且其他东西引用它并不重要。所以你真正想要的是与Location的一系列单向关系。由于您已将Location映射为非拥有端(通过“mappedBy”参数),您所要做的就是从Location中删除@OneToOne
s。您所需要的只是,例如:
@OneToOne
@JoinColumn(name="origin")
public Location origin;
这表示“origin”属性是Location,其主键存储在此实体映射到的表的“origin”字段中。
就此而言,我希望所有这些都不是真正的一对一关系。至少LineItem是一对多的。我无法想象两个订单项永远不会有相同的来源或目的地。
顺便说一下,optional=false
是默认值,但如果您认为它会阻止该字段为空,则不会。可选参数只告诉JPA如果缺少外键引用的行,是否抛出异常。
这是一种高级概述。如果你不理解其中一些问题,请进一步询问。 Hibernate Annotations guide应该可以帮助你理解它的很多内容,让hibernate为你生成一个数据库模式也是非常有帮助的,这样你就可以看到它是否理解了你所知道的表格结构。