迷失了JPA @OneToMany和复合PK

时间:2010-08-14 07:43:48

标签: hibernate orm jpa

我很遗憾用JPA注释映射以下结构。

+===========+             +====================+
| Offer     |             | Text               |
+-----------+ 1      0..* +--------------------+
| id (pk)   |-------------| textkey (pk)       |
| namekey   |             | languagecode (pk)  |
| ...       |             | text               |
+===========+             | ...                |
                          +====================+

因此,每个Offer都有一个知道i18n的名称。因为我在应用程序中反复出现相同的情况(Offer也有i18n注释,文章有i18n名称等)我希望有一个带有复合主键的Text实体。对于每个密钥,存在与支持的语言一样多的记录。文字样本:

+=====================================+
| textkey    | languagecode | text    |
+=====================================+
| offer5Name | en           | foo     |
| offer5Name | fr           | bar     |
| offer6Name | en           | hello   |
...

Offer实体会将Text#textkey存储在其namekey列中。

在Java方面,我希望提供一组名称,甚至更好的名称映射,这样我就可以使用Text getName(String language)而不是Set<Text> getNames()的方法。

我已经拥有的是Text及其复合主键TextPK:

@Entity
public class Text {

  @EmbeddedId
  private TextPK primaryKey;

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

PK

@Embeddable
public class TextPK implements Serializable {

  @Column(name = "textkey")
  private Long key;

  @Column(name = "languagecode")
  @Enumerated(EnumType.STRING)
  private LanguageCode languageCode;

问题:如何在Offer类中注释'names'成员变量以获得我需要的内容?

1 个答案:

答案 0 :(得分:2)

好的,我再次回答我自己的问题......

JPA 1.0不支持单向OneToMany(http://en.wikibooks.org/wiki/Java_Persistence/OneToMany#Example_of_a_JPA_2.0_unidirectional_OneToMany_relationship_database),这就是我最终会得到的结果。

对我的案例最有效的方法是创建一个中间TextCollection实体。每个域实体(例如Offer)对于其每个文本属性(名称,描述等)都与TextCollection具有OneToOne关系。集合实体本身只有与Text的id和双向OneToMany关系。

@Entity
@Table(name = "textcollection")
public class TextCollection {

  @Id
  @Column(name = "textkey")
  private String key;

  @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "textCollection")
  private final Set<Text> texts = new HashSet<Text>();


@Entity
@Table(name = "text")
public class Text {

  @EmbeddedId
  private TextPK primaryKey;

  @Column(name = "text", nullable = false)
  private String text;

  @ManyToOne
  @JoinColumn(name = "textkey", insertable = false, updatable = false)
  private TextCollection textCollection;

@Entity
@Table(name = "offer")
public class Offer {

  @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
  @JoinColumn(name = "namekey", nullable = false, insertable = true)
  private TextCollection name;