持久化多对一类时,外键约束违规

时间:2010-04-11 06:20:47

标签: jpa ejb eclipselink

我在尝试将多个实体持久化时遇到错误:

  

内部异常:org.postgresql.util.PSQLException:错误:表“插入或更新”概念违反了外键约束“concept_concept_class_fk”     细节:表“concept_class”中不存在键(concept_class_id)=(Concept)。   错误代码:0   调用:INSERT INTO概念(concept_key,description,label,code,concept_class_id)VALUES(?,?,?,?,?)           bind => [27,description_1,label_1,code_1,Concept]   查询:InsertObjectQuery(com.mirth.results.entities.Concept [conceptKey = 27])           at com.sun.ejb.containers.BaseContainer.checkExceptionClientTx(BaseContainer.java:3728)           at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:3576)           at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1354)           ... 101更多

以下是尝试保留它的方法。我把评论放在哪一行:

@Override
public void loadConcept(String metaDataFilePath, String dataFilePath) throws Exception {
    try {
        ConceptClassMetaData conceptClassMetaData = (ConceptClassMetaData) ModelSerializer.getInstance().fromXML(FileUtils.readFileToString(new File(metaDataFilePath), "UTF8"));


        em.executeNativeQuery(conceptClassMetaData.getCreateStatement());

        ConceptClassRow conceptClassRow = conceptClassMetaData.getConceptClassRow();

        ConceptClass conceptClass = em.findByPrimaryKey(ConceptClass.class, conceptClassRow.getId()); 
        if (conceptClass == null) {
            conceptClass = new ConceptClass(conceptClassRow.getId());
        }
        conceptClass.setLabel(conceptClassRow.getLabel());
        conceptClass.setOid(conceptClassRow.getOid());
        conceptClass.setDescription(conceptClassRow.getDescription());

        conceptClass = em.merge(conceptClass);            

        DataParser dataParser = new DataParser(conceptClassMetaData, dataFilePath);
        for (ConceptModel conceptModel : dataParser.getConceptRows()) {
            ConceptFilter<Concept> filter = new ConceptFilter<Concept>(Concept.class);
            filter.setCode(conceptModel.getCode());
            filter.setConceptClass(conceptClass.getLabel());
            List<Concept> concepts = em.findAllByFilter(filter);

            Concept concept = new Concept();
            if (concepts != null && !concepts.isEmpty()) {
                concept = concepts.get(0);
            }
            concept.setCode(conceptModel.getCode());
            concept.setDescription(conceptModel.getDescription());
            concept.setLabel(conceptModel.getLabel());
            concept.setConceptClass(conceptClass);
            concept = em.merge(concept);  //THIS LINE CAUSES THE ERROR!

        }
    } catch (Exception e) {            
        e.printStackTrace();
        throw e;
    }

}

...

以下是两个实体的定义方式:

@Entity
@Table(name = "concept")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="concept_class_id", discriminatorType=DiscriminatorType.STRING)
public class Concept extends KanaEntity {
    @Id
    @Basic(optional = false)
    @Column(name = "concept_key")
    protected Integer conceptKey;
    @Basic(optional = false)
    @Column(name = "code")
    private String code;
    @Basic(optional = false)
    @Column(name = "label")
    private String label;
    @Column(name = "description")
    private String description;
    @JoinColumn(name = "concept_class_id", referencedColumnName = "id")
    @ManyToOne
    private ConceptClass conceptClass;

...


@Entity
@Table(name = "concept_class")
public class ConceptClass extends KanaEntity {
    @Id
    @Basic(optional = false)
    @Column(name = "id")
    private String id;
    @Basic(optional = false)
    @Column(name = "label")
    private String label;
    @Column(name = "oid")
    private String oid;
    @Column(name = "description")
    private String description;
....

而且,重要的是正在生成的sql:

  

INSERT INTO concept_class(id,oid,description,label)VALUES(?,?,?,?)bind =&gt; [ LOINC_TEST ,2.16.212.31.231.54,这是LOINC_TEST的元数据文件,loinc_test]

     

INSERT INTO概念(concept_key,description,label,code,concept_class_id)VALUES(?,?,?,?,?)bind =&gt; [27,description_1,label_1,code_1,概念]

这是失败的原因很明显:它为concept_class_id插入了 Concept 这个词。它应该插入单词 LOINC_TEST 。我无法弄清楚它为什么使用这个词。我使用调试器来查看Concept和ConceptClass实例,它们都没有包含这个单词。我正在使用eclipselink。有谁知道为什么会这样?

1 个答案:

答案 0 :(得分:0)

列concept_class_id有两个相互矛盾的定义。

列concept_class_id出现在类Concept的@DiscriminatorColumn和@JoinColumn注释中。你不能这样做。这两个注释正在争取控制表概念中的列concept_class_id。 @DiscriminatorColumn碰巧赢了。这就是为什么类名“Concept”出现在您期望ConceptClass id的SQL绑定中。

顺便说一句,@ DiscriminatorColumn仅在多个类共享一个表时才有用。 @D / C记录一行代表哪一类。如果只有Concept类的对象存储在概念表中,则可以删除@DiscriminatorColumn。除非你在表中有多个类,否则@ D / C是没有意义的。

总结一下,修正包括:

  • 在Concept的@DiscriminatorColumn注释
  • 中更改“名称”
  • 在Concept.conceptClass的@JoinColumn注释中更改“name”
  • 删除类Concept
  • 上的@DiscriminatorColumn注释

HTH