JPA与OneToMany的反向连接导致多个具有给定标识符的行

时间:2016-08-08 20:20:15

标签: java hibernate jpa java-ee

我有一个方便的关系设置,其中一个实体与另一个实体具有一对多关系,并且与另一个实体具有多对一关系。因此,LISTING有许多LISTING_LINE_ITEMS,而那些LISTING_LINE_ITEMS有一个SERVICE_PERIOD,但SERVICE_PERIOD有许多LISTING_LINE_ITEMS。我试图用JPA的@JoinTable描述这种关系如下:

LISTING

@OneToMany
@JoinTable (name = "LISTING_LINE_ITEM", joinColumns = @JoinColumn (name = "listing_id"), inverseJoinColumns = @JoinColumn (name = "service_period_id"))
Set<ServicePeriod>                      servicePeriods;

LISTING_LINE_ITEM

@ManyToOne (fetch = FetchType.EAGER)
@JoinColumn (name = "listing_id", nullable = false)
Listing                   listing;

@ManyToOne (fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinColumn (name = "service_period_id")
ServicePeriod             servicePeriod;

SERVICE_PERIOD

@ManyToOne
@JoinTable (name = "LISTING_LINE_ITEM", joinColumns = @JoinColumn (name = "service_period_id"), inverseJoinColumns = @JoinColumn (name = "listing_id"))
Listing              listing;

明显的目标是能够轻松获取ServicePeriod的{​​{1}}个列表或Listing的{​​{1}}个列表。目前设置方式我得到了例外:

Listing

我认为这是因为列表中的ListingLineItems引用了同一个ServicePeriod。我确信有一种方法可以完成我之后所做的事情,但我不知道它是什么。

1 个答案:

答案 0 :(得分:1)

你似乎确实遇到了一些问题。在技​​术/ JPA方面:

  • 您不能将LISTING_LINE_ITEM用作连接表和实体表。这有几个原因,但主要原因是你会混淆JPA:它会尝试以不同的,不兼容的方式使用该表来实现这两个目的。

  • JPA中的
  • ,双向关系完全由一方拥有;另一方使用其关系注释的mappedBy属性来引用拥有方。

但是你也有数据设计问题。您将订单项的服务期限限制为与同一商家信息分开关联的服务期限之一的约束构成

  • 非关键字段之间的功能相关性,如果列表ID不是订单项键的一部分,或者

  • 对密钥子集的功能依赖。

在第一种情况下,您的数据不能处于第三范式;在第二种情况下,他们甚至不能成为第二种正常形式。使用JPA对此进行建模的麻烦部分来自于低标准化水平。

正确规范化数据可以在多个级别上轻松实现。为此,您需要删除列表和订单项之间的直接关联,而是通过服务期将其关联起来。然后你会:

Listing&lt; - 一对多 - &gt; ServicePeriod&lt; - 一对多 - &gt; LineItem

当然,这会对您的应用程序的结构产生影响,但它可能是一个长期的开发和维护胜利,甚至是可用性的胜利,因为应用程序可以与您的应用程序的自然结构保持一致这样的数据。如果您愿意,可以在Listing实体上添加方法,以便在某种程度上管理ListingLineItem,就好像它们直接属于Listing s,而反之亦然< / em>的

该数据组织看起来像这样:

LISTING

@OneToMany(mappedBy = "listing",
        fetch = FetchType.EAGER,
        cascade = CascadeType.PERSIST)
Set<ServicePeriod> servicePeriods;

SERVICE_PERIOD

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "listing_id")
Listing listing;

@OneToMany(mappedBy = "servicePeriod",
        fetch = FetchType.EAGER,
        cascade = CascadeType.PERSIST)
Set<ListingLineItem> lineItems;

LISTING_LINE_ITEM

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "service_period_id")
ServicePeriod servicePeriod;

如果您无法或多或少地重新构建数据 ,那么您就会陷入困境,无法完全向JPA描述。我想象Listing&lt; - &gt;的单独联接表ServicePeriod,从实体表中为行项目提供的非JPA FK约束,当然还有各种双向关系的正确形式。