2009-07-08 1 views
4

私のデータベースには2つのエンティティがあります。会社と人。会社は多くの人を持つことができますが、人は会社を1つしか持たないことが必要です。表の構造は次のようになります。Eclipselink/JPAでは、プライマリコンポジットキーとフィールドを共有する外部コンポジットキーを使用できますか?

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)をオーバーライドします。

これまでのところとても良いです。しかし、私は問題に直面しています。私が既存の会社を持っていてPersonを作って、そのPersonとCompanyに関連させて会社を存続させると、その人物が挿入されたときには、その関連は保存されません。たとえば、私のメインコードは次のようになります:

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);

これでエラーはなくなります。データベースでは、COMP_IDフィールドにPersonレコードがnullで挿入されていました。 FINEへのEclipseLinkデバッグログを設定すると、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は、これらのオプションを指定して読み取り専用に設定しなくても、列を2度使用できないことを示す起動に失敗します。

答えて

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

あなたは手の込んだてもらえますか?これを行うことの効果は何ですか?どの段階で、所有者の属性にその値が設定されているとしますか? – djna

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 { 
4

をannoted。正しく再コンパイル/デプロイされていることを確認してください。 どのバージョンをお使いですか?

また、Companyオブジェクトに有効なIDが設定されていることを確認してください。

また、入れてみてください、あなたの所有者フィールドの@Columnで

insertable = false, updatable = false 

及び更新可能な全体の外部キーに挿入/を残すことができます。

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; 
} 
関連する問題