我有以下数据库表:
因此,我使用Netbeans 6.9.1生成JPA实体类和controller / dao代码来处理这个问题。它工作得很好,我只需要向Party Entity bean添加一个注释:@GeneratedValue(strategy = GenerationType.IDENTITY)。 Person实体bean不需要这样做,因为它应该始终具有它所连接的Party的pk值。
所以这就是我创造一个人的方法:
PartyJpaController parController = new PartyJpaController();
PersonJpaController perController = new PersonJpaController();
Party par = new Party();
Person per = new Person();
par.setComment("jalla");
per.setName("Per Vers");
parController.create(par);
per.setPrsPtyId(par.getPtyId()); // <== why do I need to set this ...
Long partyId = par.getPtyId();
par.setPerson(per); // <== ... when this explicitly expresses the relationship?
perController.create(per);
parController.edit(par);
Party foundParty = parController.findParty(partyId);
Person foundPerson = foundParty.getPerson();
System.err.println(foundPerson.getName());
这很好用。但为什么我必须显式设置Person bean的pk?它与党有识别关系。如果我跳过它,我会
java.lang.IllegalArgumentException: An instance of a null PK has been incorrectly provided for this find operation.
perController.create(per)中的,这是由Netbeans生成的代码:
EntityManager em = null;
try {
em = getEntityManager();
em.getTransaction().begin();
Party party = person.getParty();
if (party != null) {
party = em.getReference(party.getClass(), party.getPtyId()); // <== Exception thrown here
person.setParty(party);
}
em.persist(person);
if (party != null) {
party.setPerson(person);
party = em.merge(party);
}
em.getTransaction().commit();
所以,我认为Netbeans生成的代码没有完全用于识别关系?编码的最佳方法是什么?
使用的软件:Eclipselink版本2.1.1 Postgresql 8.4 Netbeans 6.9.1 Java / JDK 1.6.0_21
这是我的bean,它们是由来自模式的netbeans 6.9.1生成的,除了Party中的@GeneratedValue(策略= GenerationType.IDENTITY),我为了使用串行/序列pk生成而添加了的PostgreSQL。
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.martinsolaas.webmarin.jpa; import java.io.Serializable; import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.MapsId; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.OneToOne; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; /** * * @author jms */ @Entity @Table(name = "person", catalog = "webmarin", schema = "webmarin") @NamedQueries({ @NamedQuery(name = "Person.findAll", query = "SELECT p FROM Person p"), @NamedQuery(name = "Person.findByPrsPtyId", query = "SELECT p FROM Person p WHERE p.prsPtyId = :prsPtyId"), @NamedQuery(name = "Person.findByName", query = "SELECT p FROM Person p WHERE p.name = :name"), @NamedQuery(name = "Person.findByCellphone", query = "SELECT p FROM Person p WHERE p.cellphone = :cellphone"), @NamedQuery(name = "Person.findByOfficephone", query = "SELECT p FROM Person p WHERE p.officephone = :officephone")}) public class Person implements Serializable { private static final long serialVersionUID = 1L; @Id @Basic(optional = false) @Column(name = "prs_pty_id", nullable = false) @MapsId private Long prsPtyId; @Column(name = "name", length = 255) private String name; @Column(name = "cellphone", length = 55) private String cellphone; @Column(name = "officephone", length = 55) private String officephone; @JoinColumn(name = "prs_pty_id", referencedColumnName = "pty_id", nullable = false, insertable = false, updatable = false) @OneToOne(optional = false) private Party party; public Person() { } public Person(Long prsPtyId) { this.prsPtyId = prsPtyId; } public Long getPrsPtyId() { return prsPtyId; } public void setPrsPtyId(Long prsPtyId) { this.prsPtyId = prsPtyId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCellphone() { return cellphone; } public void setCellphone(String cellphone) { this.cellphone = cellphone; } public String getOfficephone() { return officephone; } public void setOfficephone(String officephone) { this.officephone = officephone; } public Party getParty() { return party; } public void setParty(Party party) { this.party = party; } @Override public int hashCode() { int hash = 0; hash += (prsPtyId != null ? prsPtyId.hashCode() : 0); return hash; } @Override public boolean equals(Object object) { // TODO: Warning - this method won't work in the case the id fields are not set if (!(object instanceof Person)) { return false; } Person other = (Person) object; if ((this.prsPtyId == null && other.prsPtyId != null) || (this.prsPtyId != null && !this.prsPtyId.equals(other.prsPtyId))) { return false; } return true; } @Override public String toString() { return "com.martinsolaas.webmarin.jpa.Person[prsPtyId=" + prsPtyId + "]"; } }
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.martinsolaas.webmarin.jpa; import java.io.Serializable; import java.util.List; import javax.persistence.Basic; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.MapsId; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.OneToOne; import javax.persistence.Table; /** * * @author jms */ @Entity @Table(name = "party", catalog = "webmarin", schema = "webmarin") @NamedQueries({ @NamedQuery(name = "Party.findAll", query = "SELECT p FROM Party p"), @NamedQuery(name = "Party.findByPtyId", query = "SELECT p FROM Party p WHERE p.ptyId = :ptyId"), @NamedQuery(name = "Party.findByComment", query = "SELECT p FROM Party p WHERE p.comment = :comment")}) public class Party implements Serializable { private static final long serialVersionUID = 1L; @Id @Basic(optional = false) @Column(name = "pty_id", nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private Long ptyId; @Basic(optional = false) @Column(name = "comment", nullable = false, length = 2147483647) private String comment; @JoinTable(name = "party_relationship", joinColumns = { @JoinColumn(name = "parent_pty_id", referencedColumnName = "pty_id", nullable = false)}, inverseJoinColumns = { @JoinColumn(name = "child_pty_id", referencedColumnName = "pty_id", nullable = false)}) @ManyToMany private List partyList; @ManyToMany(mappedBy = "partyList") private List partyList1; @OneToOne(cascade = CascadeType.ALL, mappedBy = "party") private Person person; @OneToOne(cascade = CascadeType.ALL, mappedBy = "party") private Company company; public Party() { } public Party(Long ptyId) { this.ptyId = ptyId; } public Party(Long ptyId, String comment) { this.ptyId = ptyId; this.comment = comment; } public Long getPtyId() { return ptyId; } public void setPtyId(Long ptyId) { this.ptyId = ptyId; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } public List getPartyList() { return partyList; } public void setPartyList(List partyList) { this.partyList = partyList; } public List getPartyList1() { return partyList1; } public void setPartyList1(List partyList1) { this.partyList1 = partyList1; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } public Company getCompany() { return company; } public void setCompany(Company company) { this.company = company; } @Override public int hashCode() { int hash = 0; hash += (ptyId != null ? ptyId.hashCode() : 0); return hash; } @Override public boolean equals(Object object) { // TODO: Warning - this method won't work in the case the id fields are not set if (!(object instanceof Party)) { return false; } Party other = (Party) object; if ((this.ptyId == null && other.ptyId != null) || (this.ptyId != null && !this.ptyId.equals(other.ptyId))) { return false; } return true; } @Override public String toString() { return "com.martinsolaas.webmarin.jpa.Party[ptyId=" + ptyId + "]"; } }
最终,这是架构SQL
CREATE SEQUENCE webmarin.party_pty_id_seq; CREATE TABLE webmarin.party ( pty_id BIGINT NOT NULL DEFAULT nextval('webmarin.party_pty_id_seq'), comment TEXT NOT NULL, CONSTRAINT pty_pk PRIMARY KEY (pty_id) ); ALTER SEQUENCE webmarin.party_pty_id_seq OWNED BY webmarin.party.pty_id; CREATE TABLE webmarin.company ( cmp_pty_id BIGINT NOT NULL, name VARCHAR(255) NOT NULL, CONSTRAINT cmp_pk PRIMARY KEY (cmp_pty_id) ); CREATE TABLE webmarin.party_relationship ( parent_pty_id BIGINT NOT NULL, child_pty_id BIGINT NOT NULL, CONSTRAINT ptr_pk PRIMARY KEY (parent_pty_id, child_pty_id) ); CREATE TABLE webmarin.person ( prs_pty_id BIGINT NOT NULL, name VARCHAR(255), cellphone VARCHAR(55), officephone VARCHAR(55), CONSTRAINT prs_pk PRIMARY KEY (prs_pty_id) ); ALTER TABLE webmarin.party_relationship ADD CONSTRAINT parent_party_party_relationship_fk FOREIGN KEY (parent_pty_id) REFERENCES webmarin.party (pty_id) ON DELETE NO ACTION ON UPDATE NO ACTION NOT DEFERRABLE; ALTER TABLE webmarin.party_relationship ADD CONSTRAINT child_party_party_relationship_fk FOREIGN KEY (child_pty_id) REFERENCES webmarin.party (pty_id) ON DELETE NO ACTION ON UPDATE NO ACTION NOT DEFERRABLE; ALTER TABLE webmarin.person ADD CONSTRAINT party_person_fk FOREIGN KEY (prs_pty_id) REFERENCES webmarin.party (pty_id) ON DELETE NO ACTION ON UPDATE NO ACTION NOT DEFERRABLE; ALTER TABLE webmarin.company ADD CONSTRAINT party_company_fk FOREIGN KEY (cmp_pty_id) REFERENCES webmarin.party (pty_id) ON DELETE NO ACTION ON UPDATE NO ACTION NOT DEFERRABLE;
答案 0 :(得分:0)
JPA 2.0大大改进了对派生标识符的支持,其中Id
和MapsId
注释(现在应该首选它们)可以在XxxToOne
上使用关联。以下是从规范中取得的一个例子:
2.4.1.3派生身份的例子
...
示例4:
父实体有一个简单的主要实体 键:
@Entity public class Person { @Id String ssn; ... }
案例(a):从属实体具有单个主键属性 由关系映射 属性。的主要关键
MedicalHistory
的类型为String
。@Entity public class MedicalHistory { // default join column name is overridden @Id @OneToOne @JoinColumn(name="FK") Person patient; ... }
示例查询:
SELECT m FROM MedicalHistory m WHERE m.patient.ssn = '123-45-6789'
案例(b):从属实体具有单个主键属性 对应关系 属性。主键属性 与...的基本类型相同 父实体的主键。该
MapsId
注释应用于 关系属性表示 主键由。映射 关系属性。@Entity public class MedicalHistory { @Id String id; // overriding not allowed ... // default join column name is overridden @MapsId @JoinColumn(name="FK") @OneToOne Person patient; ... }
示例查询:
SELECT m FROM MedicalHistory m WHERE m.patient.ssn = '123-45-6789'
我认为MapsId
可能就是你要找的东西。
跟进:而不是:
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@Column(name = "prs_pty_id", nullable = false)
@MapsId
private Long prsPtyId;
@Column(name = "name", length = 255)
private String name;
@Column(name = "cellphone", length = 55)
private String cellphone;
@Column(name = "officephone", length = 55)
private String officephone;
@JoinColumn(name = "prs_pty_id", referencedColumnName = "pty_id", nullable = false, insertable = false, updatable = false)
@OneToOne(optional = false)
private Party party;
...
}
试试这个:
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@Column(name = "prs_pty_id", nullable = false)
private Long prsPtyId;
@Column(name = "name", length = 255)
private String name;
@Column(name = "cellphone", length = 55)
private String cellphone;
@Column(name = "officephone", length = 55)
private String officephone;
@MapsId
@JoinColumn(name = "prs_pty_id", referencedColumnName = "pty_id")
@OneToOne
private Party party;
...
}