I have a database design with sample records as below. Both Question and Answer tables share the same Content table that stores their wordings translation. By specifying 1 in the indicator of Content, I know that the reference of Content refer to the id of Question (2 for Answer).
Question
+---------+----------+
| id (PK) | sequence |
+---------+----------+
| 1 | 1 |
+---------+----------+
Answer
+---------+----------+
| id (PK) | sequence |
+---------+----------+
| 1 | 1 |
+---------+----------+
| 2 | 2 |
+---------+----------+
Content
+---------+-----------+----------------+----------+------------------+
| 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 |
+---------+-----------+----------------+----------+------------------+
I try to link the relationship with JPA using following code:
@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;
}
It throws following exception during compile time:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: jpatest.model.Content column: reference (should be mapped with insert="false" update="false") at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:709) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:731) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:753) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:506) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] at org.hibernate.mapping.RootClass.validate(RootClass.java:270) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] at org.hibernate.cfg.Configuration.validate(Configuration.java:1360) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1851) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:857) ~[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final] ... 48 common frames omitted
However, if I put insertable = false in both @ManyToOne @JoinColumn, I can run below sample code but the result is not my expectation. All of the reference in Content are null. Any clue to modify the model?
@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);
}
}