当前位置: 首页 > 知识库问答 >
问题:

JPA将两个表与一个具有常量值的表连接起来

韩靖琪
2023-03-14

我有一个样本记录如下的数据库设计。问题和答案表共享相同的内容表,存储它们的措辞翻译。通过在内容指示符中指定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.hhibernate引起。MappingException:实体jpatest.model的映射中出现重复列。内容列:引用(应使用insert=“false”update=“fa”映射)位于org.hhibernate.mapping.PersistentClass.checkColumnDuplication(PersistenceClass.java:709)~[hibernate-core-4.3.11.Final.jar:4.3.11.Final],位于org.hHibernate.mapping.PerssistentClass.checkPropertyColumnDuplicationorg.hhibernate.mapping.PersistentClass.checkColumnDuplication(PersistenceClass.java:753)~[hibernate-core-4.3.11.Final.jar:4.3.11.Final],位于org.hhi伯nate.mapging.PersiteClass.validate(PersintentClass.java:506)~[hibernate-core-4.3.11.Final.jar:4.3.11.Finall],位于org.hhibernate.cfg.Configuration.validate(Configuration.java:1360)~[hibernate-core-4.3.11.Final.jar:4.3.11.Final],位于org.hhipernate.cfg.Configuration.buildSessionFactory(Configurance.java:1851)~[hibernate-core-4.3.11.Final.jar:4.3.11.Final],位于.org.hhibertate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform~[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]…省略48个公共帧

然而,如果我将< code>insertable = false放入两个< code > @ ManyToOne < code > @ join column 中,我可以运行下面的示例代码,但结果不是我所期望的。内容中的所有引用均为空。有什么修改模型的线索吗?

@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个答案

彭正谊
2023-03-14

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

alter table Content add constraint FK_2l306mlep79l4pr7i0ltcbf7y foreign key (reference) references Answer
alter table Content add constraint FK_2l306mlep79l4pr7i0ltcbf7y foreign key (reference) references Question

这将以静默方式失败,因为外键具有相同的名称:

Unsuccessful: alter table Content add constraint FK_2l306mlep79l4pr7i0ltcbf7y foreign key (reference) references Question

如果现有数据库没有此约束,则可能没有问题。您在引用列中没有看到任何内容的原因是您没有尝试在其中插入任何内容,您应该这样做:

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]

如果您有两列要处理,为什么不将一列引用问题,另一列引用答案

@ManyToOne
private Question question;   
@ManyToOne
private Answer answer;

然后,您需要测试代码中哪一个是空的,真的很难看,但并不比一直测试引用更糟糕。最好将Content制作为@MappedSuperclass,并创建两个新实体, ,每个实体都扩展 。这将意味着更多的桌子,但这是一个干净的设计

 类似资料:
  • 问题内容: 我有以下问题。我想加入两个表。 第一个表具有如下条目: 第二个表是这样构建的: 我的结果应显示以下内容 我只是不知道如何解决这个问题。 仅使用sql selects可能需要此功能吗? 亲切的问候 问题答案: 并不是那么困难,但是-就像你被告知的那样,你宁愿不要那样做。

  • 问题是@ManyToOne@Joincolumn ID_REPORT(它是一个主键)和@Joincolumn ID_TEMPLATE_DEFAULT 实体映射中的重复列:CurReport 列:id_report(应使用插入=“false”更新=“false”进行映射) 代码 第一桌CUR_TEMPLATE 第二个表CUR_REPORTS 第一个表CUR_REPORTS实体当前报表 第二个表CUR

  • 试图确定是否可以创建一个连接表的查询,表一比表二小,表二有多个匹配表一条目的引用,查询将输出一个连接,其中表一的长度保留,但您只需添加更多列。我不确定这是否有意义,所以这里是我想要的一个例子 更新!! 保持原来的查询并使用PHP处理结果,也获得了很好的性能。让我知道如果你需要我张贴我的代码。

  • 问题内容: 给定以字典为元素的列表,我想产生一个新列表,其中包含一组连接的字典。每个字典都保证有一个称为“索引”的键,但除此之外可以有任意键集。非索引键永远不会在列表之间重叠。例如,想象以下两个列表: (永远不会出现在中,因为它出现在中,并且类似地,永远不会出现在中,因为它出现在中) 我想产生一个联合列表: 在Python中最有效的方法是什么? 问题答案: 编辑 :由于不能保证被排序(不按特定顺序

  • 问题内容: 我有两个表帐户和余额 我想加入这两个表并获取特定cid的最大日期余额。 输出结果为- 问题答案: 您需要使用两个子查询,如下所示: 输出: 客户编号 姓名 移动的 日期 平衡 1个 美国广播公司 12345 2013年9月20日00:00:00 + 0000 300 2个 XYZ 98475 2013年9月21日00:00:00 + 0000 600 看到这个SQLFiddle

  • 它重复显示每个房间类型的酒店名称匹配该酒店id,但我想显示所有房间类型的酒店名称一次。我怎样才能做到这一点? 谢谢。