在JPA中建模隐式的多对多关系

时间:2016-03-30 07:34:52

标签: jpa eclipselink

考虑我想在JPA中表示的以下遗留数据模型:

  • 语言包含idname
  • 语言描述包含一个由idlanguage_id组成的复合主键,另外还有一个description,因此每个翻译都有一个条目用于每种语言。
  • 文章有(国际化的)描述,由上述languagedescription_id确定。

现在,我的第一种方法是对像

这样的实体进行建模
@Entity
public class Language {

    @Id
    @Column(length = 3)
    private String id;

    private String languageDescription;

    // ...
}

@Embeddable
public class LanguageDescriptionId implements Serializable {

    @Column(length = 9)
    private String id;

    @Column(length = 3)
    private String languageId;

    // ...
}

@Entity
public class LanguageDescription {

    @EmbeddedId
    private LanguageDescriptionId languageDescriptionId;

    @ManyToOne
    @MapsId(value = "languageId")
    private Language language;

    @Column(length = 60)
    private String description;

    // ...
}

@Entity
public class Article {

    @Id
    private String id;

    @ManyToOne
    private LanguageDescription languageDescription;
}

其中a)不正确,因为技术上文章可以有一个翻译列表(理想情况下是语言到语言描述的映射,以便轻松获取给定语言的翻译)和b)导致数据库情况,即我的ORM(EclipseLink)将languagedescription的主键列添加到article表,尽管文章仅引用languagedescription_id以防止多个冗余条目。用

替换Article实体时
@Entity
public class Article {

    @Id
    private String id;

    @ManyToMany
    private List<LanguageDescription> languageDescriptions;
}

我的ORM创建了一个映射表,我必须手动填充该映射表,并使用冗余信息扩展(遗留)数据模型。目前我的方法是为Article实体建模,如

@Entity
public class Article {

    @Id
    private String id;

    @Column(length = 9)
    private String languageDescriptionId;
}

同时省略JPA支持并在@EntityListener中获取翻译。

现在,这种情况在JPA中是否可以自动管理,或者这些“隐含”的多对多关系没有JPA根本不支持的映射表?

实施例

public class Main {

    public static void main(String[] args) {
        final Language english = createLanguage("language_1", "English");
        final Language german = createLanguage("language_2", "German");

        createArticle1(english, german);
        createArticle2(english, german);
    }

    private static Language createLanguage(String id, String languageDescription) {
        final Language language = new Language();
        language.setId(id);
        language.setLanguageDescription(languageDescription);

        return language;
    }

    private static void createArticle1(Language english, Language german) {
        final String languageDescriptionId = "languagedescription_1";

        final LanguageDescription languageDescription1 = new LanguageDescription();
        final LanguageDescriptionId languageDescriptionId1 = new LanguageDescriptionId();
        languageDescriptionId1.setId(languageDescriptionId);
        languageDescriptionId1.setLanguageId(english.getId());
        languageDescription1.setLanguageDescriptionId(languageDescriptionId1);
        languageDescription1.setLanguage(english);
        languageDescription1.setDescription("Engine");

        final LanguageDescription languageDescription2 = new LanguageDescription();
        final LanguageDescriptionId languageDescriptionId2 = new LanguageDescriptionId();
        languageDescriptionId2.setId(languageDescriptionId);
        languageDescriptionId2.setLanguageId(german.getId());
        languageDescription2.setLanguageDescriptionId(languageDescriptionId2);
        languageDescription2.setLanguage(german);
        languageDescription2.setDescription("Motor");

        final Article article1 = new Article();
        article1.setId("a_1");
        article1.setLanguageDescriptionId(languageDescriptionId);
    }

    private static void createArticle2(Language english, Language german) {
        final String languageDescriptionId = "languagedescription_2";

        final LanguageDescription languageDescription3 = new LanguageDescription();
        final LanguageDescriptionId languageDescriptionId3 = new LanguageDescriptionId();
        languageDescriptionId3.setId(languageDescriptionId);
        languageDescriptionId3.setLanguageId(english.getId());
        languageDescription3.setLanguageDescriptionId(languageDescriptionId3);
        languageDescription3.setLanguage(english);
        languageDescription3.setDescription("Turn Signal");

        final LanguageDescription languageDescription4 = new LanguageDescription();
        final LanguageDescriptionId languageDescriptionId4 = new LanguageDescriptionId();
        languageDescriptionId4.setId(languageDescriptionId);
        languageDescriptionId4.setLanguageId(german.getId());
        languageDescription4.setLanguageDescriptionId(languageDescriptionId4);
        languageDescription4.setLanguage(german);
        languageDescription4.setDescription("Blinker");

        final Article article2 = new Article();
        article2.setId("a_2");
        article2.setLanguageDescriptionId(languageDescriptionId);
    }
}

1 个答案:

答案 0 :(得分:0)

以下内容是可能的:

@Entity
public class Article {

    @Id
    private String id;

    @Column(length = 9)
    private String languageDescriptionId;

    @OneToMany
    @JoinColumn(name="ID", referencedColumnName="LANGUAGEDESCRIPTIONID", insertable=false, updatable=false)
    private List<LanguageDescription> languageDescriptions;
}

现在上面的OneToMany不符合JPA,因为LanguageDescription有一个复合PK,所以EclipseLink和其他提供程序会抛出验证异常,它只是它的外观的一个例子。您将需要使其成为临时的或添加另一个连接列,只是为了绕过验证,然后在描述符定制器中修改或添加映射。这在jpa, eclips-link 2.5.1: OneToMany not working on columns not primary key

的答案中有所描述和显示