我有一个带有样本记录的数据库设计,如下所示。问题和答案表共享存储其措辞翻译的相同内容表。通过在内容指标中指定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);
}
}
答案 0 :(得分:1)
答案取决于数据库中是否存在约束。如果要使用实体创建数据库,则会添加约束。如果数据库已经存在,并且没有约束,请继续阅读。您可以根据需要将reference
列设置为updatable=false
和insertable=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
并创建两个新实体@MappedSuperclass
和QuestionContent
,每个实体都扩展AnswerContent
。这将意味着更多的桌子,但它是一个干净的设计。