JPA连接两个表,其中一个表具有常量值

时间:2016-03-03 10:55:05

标签: hibernate jpa

我有一个带有样本记录的数据库设计,如下所示。问题和答案表共享存储其措辞翻译的相同内容表。通过在内容指标中指定1,我知道内容的引用是指问题的ID(答案为2)。

问题

+---------+----------+
| id (PK) | sequence |
+---------+----------+
|       1 |        1 |
+---------+----------+

答案

+---------+----------+
| id (PK) | sequence |
+---------+----------+
|       1 |        1 |
+---------+----------+
|       2 |        2 |
+---------+----------+

内容

+---------+-----------+----------------+----------+------------------+
| id (PK) | indicator | reference (FK) | language | value            |
+---------+-----------+----------------+----------+------------------+
|       1 |         1 |              1 | en       | English question |
+---------+-----------+----------------+----------+------------------+
|       2 |         1 |              1 | zh_TW    | Chinese question |
+---------+-----------+----------------+----------+------------------+
|       3 |         2 |              1 | en       | English answer 1 |
+---------+-----------+----------------+----------+------------------+
|       4 |         2 |              1 | zh_TW    | Chinese answer 1 |
+---------+-----------+----------------+----------+------------------+
|       5 |         2 |              2 | en       | English answer 2 |
+---------+-----------+----------------+----------+------------------+
|       6 |         2 |              2 | zh_TW    | Chinese answer 2 |
+---------+-----------+----------------+----------+------------------+

我尝试使用以下代码链接与JPA的关系:

@Entity
public class Question
{
   @Id
   @GeneratedValue
   private Integer       id;

   @Column
   private Integer       sequence;

   @OneToMany(cascade = CascadeType.ALL)
   @JoinColumn(name = "reference", referencedColumnName = "id")
   @Where(clause = "indicator = 1")
   private List<Content> contents = new ArrayList<Content>();
}

@Entity
public class Answer
{
   @Id
   @GeneratedValue
   private Integer id;

   @Column
   private Integer sequence;

   @OneToMany(cascade = CascadeType.ALL)
   @JoinColumn(name = "reference", referencedColumnName = "id")
   @Where(clause = "indicator = 2")
   private List<Content> contents = new ArrayList<Content>();
}

@Entity
public class Content
{
   @Id
   @GeneratedValue
   private Integer  id;

   @Column
   private Integer  indicator;

   @Column
   private String   language;

   @Column
   private String   value;

   @ManyToOne
   @JoinColumn(name = "reference", referencedColumnName = "id", updatable = false)
   @Filter(name = "questionIndicator", condition = "indicator = 1")
   private Question question;

   @ManyToOne
   @JoinColumn(name = "reference", referencedColumnName = "id", updatable = false)
   @Filter(name = "answerIndicator", condition = "indicator = 2")
   private Answer   answer;
}

它在编译期间抛出以下异常:

  

引起:org.hibernate.MappingException:实体映射中的重复列:jpatest.model.Content列:引用(应使用insert =&#34映射; false&#34; update =&#34; false&# 34)       在org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:709)〜[hibernate-core-4.3.11.Final.jar:4.3.11.Final]       在org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:731)〜[hibernate-core-4.3.11.Final.jar:4.3.11.Final]       在org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:753)〜[hibernate-core-4.3.11.Final.jar:4.3.11.Final]       在org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:506)〜[hibernate-core-4.3.11.Final.jar:4.3.11.Final]       在org.hibernate.mapping.RootClass.validate(RootClass.java:270)~ [hibernate-core-4.3.11.Final.jar:4.3.11.Final]       在org.hibernate.cfg.Configuration.validate(Configuration.java:1360)〜[hibernate-core-4.3.11.Final.jar:4.3.11.Final]       在org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1851)〜[hibernate-core-4.3.11.Final.jar:4.3.11.Final]       在org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl $ 4.perform(EntityManagerFactoryBuilderImpl.java:857)~ [hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]       ...省略了48个常见帧

但是,如果我将insertable = false放在@ManyToOne @JoinColumn中,我可以在示例代码下运行,但结果不是我的预期。 Content中的所有引用都为null。修改模型的任何线索?

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class ApplicationTest
{
   private static final String ENGLISH = "en";
   private static final String CHINESE = "zh_TW";

   @Autowired
   private AnswerRepository    answerRepository;

   @Autowired
   private ContentRepository   contentRepository;

   @Autowired
   private QuestionRepository  questionRepository;

   private void saveQuestion(String english, String chinese, int sequence)
   {
      Question question = new Question();
      question.setSequence(sequence);
      question = questionRepository.save(question);

      Content englishContent = new Content();
      englishContent.setQuestion(question);
      englishContent.setIndicator(1);
      englishContent.setValue(english);
      englishContent.setLanguage(ENGLISH);
      englishContent = contentRepository.save(englishContent);

      Content chineseContent = new Content();
      chineseContent.setQuestion(question);
      chineseContent.setIndicator(1);
      chineseContent.setValue(chinese);
      chineseContent.setLanguage(CHINESE);
      chineseContent = contentRepository.save(chineseContent);
   }

   private void saveAnswer(String english, String chinese, int sequence)
   {
      Answer answer = new Answer();
      answer.setSequence(sequence);
      answer = answerRepository.save(answer);

      Content englishContent = new Content();
      englishContent.setAnswer(answer);
      englishContent.setIndicator(2);
      englishContent.setValue(english);
      englishContent.setLanguage(ENGLISH);
      englishContent = contentRepository.save(englishContent);

      Content chineseContent = new Content();
      chineseContent.setAnswer(answer);
      chineseContent.setIndicator(2);
      chineseContent.setValue(chinese);
      chineseContent.setLanguage(CHINESE);
      chineseContent = contentRepository.save(chineseContent);
   }

   @Test
   public void test() throws Exception
   {
      saveQuestion("English question", "Chinese question", 1);
      saveAnswer("English answer 1", "Chinese answer 1", 1);
      saveAnswer("English answer 2", "Chinese answer 2", 2);
   }
}

1 个答案:

答案 0 :(得分:1)

答案取决于数据库中是否存在约束。如果要使用实体创建数据库,则会添加约束。如果数据库已经存在,并且没有约束,请继续阅读。您可以根据需要将reference列设置为updatable=falseinsertable=false,但如果它创建了数据库,则JPA会在{{1}上放置foreign key个约束位置列。

reference

这将无声地失败,因为alter table Content add constraint FK_2l306mlep79l4pr7i0ltcbf7y foreign key (reference) references Answer alter table Content add constraint FK_2l306mlep79l4pr7i0ltcbf7y foreign key (reference) references Question 具有相同的名称:

foreign key

如果您的现有数据库没有此约束,则可能不存在问题。您在Unsuccessful: alter table Content add constraint FK_2l306mlep79l4pr7i0ltcbf7y foreign key (reference) references Question 列中没有看到任何内容的原因是您没有尝试在其中插入任何内容,您应该这样做:

reference

但是,如果存在约束,则由于约束而失败:

List<Content> contents = new ArrayList<Content>();
contents.add(chineseContent);
contents.add(englishContent);
question.setContents(contents);
em.merge(question);

如果您要使用两列,为什么不建议引用Referential integrity constraint violation: "FK_2L306MLEP79L4PR7I0LTCBF7Y: PUBLIC.CONTENT FOREIGN KEY(REFERENCE) REFERENCES PUBLIC.ANSWER(ID) (1)";SQL statement: update Content set reference=? where id=? [23506-173] ,另一列引用Question

Answer

然后你需要测试你的代码中哪一个是空的,真的很难看,但并不比一直测试引用更糟糕。最好让@ManyToOne private Question question; @ManyToOne private Answer answer; 成为Content并创建两个新实体@MappedSuperclassQuestionContent,每个实体都扩展AnswerContent。这将意味着更多的桌子,但它是一个干净的设计。