首页 文章

使用Eclipselink / JPA,我可以使用与主复合键共享字段的外部复合键吗?

提问于
浏览
5

我的数据库有两个实体;公司和个人 . 公司可以有很多人,但一个人必须只有一个公司 . 表结构如下所示 .

COMPANY
----------
owner   PK
comp_id PK
c_name
PERSON
----------------
owner    PK, FK1
personid PK
comp_id  FK1
p_fname
p_sname

在我看来,我可以删除PERSON.OWNER并通过外键导出它;但是,我不能在不影响遗留代码的情况下进行此更改 .

我已将这些建模为JPA注释类;

@Entity
@Table(name = "PERSON")
@IdClass(PersonPK.class)
public class Person
    implements Serializable {

  @Id
  private String owner;

  @Id
  private String personid;

  @ManyToOne
  @JoinColumns(
    {@JoinColumn(name = "owner", referencedColumnName = "OWNER",
                 insertable = false, updatable = false),
     @JoinColumn(name = "comp_id", referencedColumnName = "COMP_ID",
                 insertable = true, updatable = true)})
  private Company company;

  private String p_fname;

  private String p_sname;

  ...and standard getters/setters...
}
@Entity
@Table(name = "COMPANY")
@IdClass(CompanyPK.class)
public class Company
    implements Serializable {

  @Id
  private String owner;

  @Id
  private String comp_id;

  private String c_name;

  @OneToMany(mappedBy = "company", cascade=CascadeType.ALL)
  private List people;

  ...and standard getters/setters...
}

我的PersonPK和CompanyPK类没有什么特别之处,它们只是作为持有所有者和ID字段的结构,并覆盖hashCode和equals(o) .

到现在为止还挺好 . 然而,当我试图处理关联时,我遇到了一个问题 . 看来如果我有一个现有的公司,并创建一个人,并将该人员与公司关联并坚持公司,则在插入人员时不会保存该关联 . 例如,我的主要代码如下所示:

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

CompanyPK companyPK = new CompanyPK();
companyPK.owner="USA";
companyPK.comp_id="1102F3";
Company company = em.find(Company.class, companyPK);

Person person = new Person();
person.setOwner("USA");
person.setPersonid("5116628123"); //some number that doesn't exist yet
person.setP_fname("Hannah");
person.setP_sname("Montana");
person.setCompany(company);
em.persist(person);

这完成没有错误;但是在数据库中我发现Person记录在COMP_ID字段中插入了一个null . 将EclipseLink调试日志记录设置为FINE,SQL查询显示为:

INSERT INTO PERSON (PERSONID,OWNER,P_SNAME,P_FNAME) VALUES (?,?,?,?)
  bind => [5116628123,USA,Montana,Hannah,]

我本来希望这个被保存,并且查询等同于

INSERT INTO PERSON (PERSONID,OWNER,COMP_ID,P_SNAME,P_FNAME) VALUES (?,?,?,?,?)
  bind => [5116628123,USA,1102F3,Montana,Hannah,]

是什么赋予了?对于复合键的一半说updatable / insertable = true而对另一半说= false是不正确的吗?如果我对外键的两个部分都有updatable / insertable = true,那么Eclipselink无法通过指定这些选项而无法使用该列两次而没有设置为readonly .

4 回答

  • 4

    你的代码应该有效 . 确保您正确地重新编译/部署它 . 你用的是什么版本?

    还要确保您的Company对象具有有效的ID集 .

    你也可以试试,

    insertable = false, updatable = false
    

    在您的所有者字段的@Column中,并保留整个外键可插入/可更新 .

  • 1

    我有同样的问题 . 我发现的解决方案是将主键字段分配为不可插入和不可更新 . 您的人员实体应如下所示:

    @Entity
    @Table(name = "PERSON")
    @IdClass(PersonPK.class)
    public class Person
        implements Serializable {
    
      @Id
      @Column(insertable = false, updatable=false)
      private String owner;
    
      @Id
      private String personid;
    
      @Id
      @Column(insertable = false, updatable=false)
      private String comp_id;
    
    
      @ManyToOne
      @JoinColumns({
         @JoinColumn(name = "owner", referencedColumnName = "OWNER"),
         @JoinColumn(name = "comp_id", referencedColumnName = "COMP_ID")
      })
      private Company company;
    
      private String p_fname;
    
      private String p_sname;
    
      ...and standard getters/setters...
    }
    
  • 0

    我这样做的方式是注释PK类中的字段,就像它们在实体上一样 .

    然后在实体中没有PK类所拥有的字段 . 如果你愿意,你可以实现直通的吸气剂

    class Person {
      .....
    
    private PersonPK pk;
    
    @Id
    public PersonPK getPk() { return pk; }
    
    @Transient
    public String getOwner() {
      return pk.getOwner();
    }
    ....
    }
    

    PersonPK需要可序列化和注释 @Embeddable

    @Embeddable
    class PersonPK implements Serializable {
    
  • 0

    除了数据库设计相当奇怪之外,这可能有效:

    @Entity
    public class Company
    {
        @EmbeddedId
        private CompanyPK key;
    
        @MapsId(value = "ownerId")
        @OneToMany
        @JoinColumn(name = "owner", referencedColumnName = "personid")
        private Person owner;
    
        @ManyToOne(mappedBy = "company")
        private List<Person> persons;
    
        @Column(name = "c_name")
        private String name;
    }
    
    @Embeddable
    public class CompanyPK
    {
        @Column(name = "comp_id")
        private String id;
    
        @Column(name = "owner")
        private String ownerId;
    }
    
    @Entity
    public class Person
    {
        @EmbeddedId
        private PersonPK key;
    
        @MapdId(value = "ownerId")
        private Person owner;
    
        @ManyToOne
        @JoinColumns({
            @JoinColumn(name = "owner", referencedColumnName = "owner")
            @JoinColumn(name = "comp_id", referencedColumnName = "comp_id")
        })
        private Company company;
    
        @Column(name = "p_fname")
        private String firstName;
    
        @Column(name = "p_sname")
        private String surName;
    }
    
    @Embeddable
    public class PersonPK
    {
        @Column(name = "personid")
        private String id;
    
        @Column(name = "owner")
        private String ownerId;
    }
    

相关问题