如何在Hibernate中将多个列映射到单个外键列

时间:2013-01-01 02:04:09

标签: hibernate jpa

我正在使用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确实被引用了很多。任何建议我直截了当都会受到赞赏。

1 个答案:

答案 0 :(得分:0)

您显示的位置配置没有任何意义。如果可以用你的全部意图解释它对JPA意味着什么:

  1. Location有一个Long“id”属性,它是一个生成的值,并映射到列loc_id。
  2. “id”属性是Dock,是Dock和Location之间一对一双向关系的非拥有端。
  3. 它也是一个LineItem,它是LineItem的一对一双向关系的非拥有端,因为 目的地。
  4. 显然这没有任何意义,对吧?如果您要在位置中拥有所有这些@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为你生成一个数据库模式也是非常有帮助的,这样你就可以看到它是否理解了你所知道的表格结构。