我有以下数据库表:
- 派对,将 pk“pty_id”连接到用于生成 pk 值的序列。
- fpk“prs_pty_id”与party.pty_id 有识别关系的人。
- company ...目前不涉及,但显然这是一种子超类设置,它可能已经使用postgresql中的子类化机制实现,但那是另一天的事了。
因此,我使用 Netbeans 6.9.1 生成 JPA 实体类和控制器/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(strategy = GenerationType.IDENTITY),我添加它是为了在postgresql中使用序列/序列pk生成。
/* * 要更改此模板,请选择工具 | 模板 * 并在编辑器中打开模板。 */ 包 com.martinsolaas.webmarin.jpa; 导入 java.io.Serializable; 导入 javax.persistence.Basic; 导入 javax.persistence.Column; 导入 javax.persistence.Entity; 导入 javax.persistence.Id; 导入 javax.persistence.JoinColumn; 导入 javax.persistence.MapsId; 导入 javax.persistence.NamedQueries; 导入 javax.persistence.NamedQuery; 导入 javax.persistence.OneToOne; 导入 javax.persistence.PrimaryKeyJoinColumn; 导入 javax.persistence.Table; /** * * @author jms */ @实体 @Table(name = "person", catalog = "webmarin", schema = "webmarin") @命名查询({ @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")}) 公共类人实现可序列化{ 私有静态最终长序列版本UID = 1L; @ID @基本(可选=假) @Column(名称=“prs_pty_id”,可为空=假) @MapsId 私人长prsPtyId; @Column(名称=“名称”,长度= 255) 私有字符串名称; @Column(name = "手机", 长度 = 55) 私人字符串手机; @Column(name = "officephone", length = 55) 私人字符串办公电话; @JoinColumn(name = "prs_pty_id", referencedColumnName = "pty_id", nullable = false, insertable = false, updatable = false) @OneToOne(可选=假) 私人派对; 公共人(){ } 公共人员(长prsPtyId){ this.prsPtyId = prsPtyId; } 公共长 getPrsPtyId() { 返回prsPtyId; } 公共无效 setPrsPtyId(长 prsPtyId){ this.prsPtyId = prsPtyId; } 公共字符串 getName() { 返回名称; } 公共无效集合名称(字符串名称){ this.name = 名称; } 公共字符串 getCellphone() { 归还手机; } 公共无效setCellphone(字符串手机){ this.cellphone = 手机; } 公共字符串 getOfficephone() { 归还办公电话; } 公共无效setOfficephone(字符串办公电话){ this.officephone = 办公电话; } 公共聚会 getParty() { 回归方; } 公共无效setParty(派对){ this.party = 派对; } @覆盖 公共 int hashCode() { 整数哈希 = 0; 哈希 += (prsPtyId != null ? prsPtyId.hashCode() : 0); 返回哈希; } @覆盖 公共布尔等于(对象对象){ // TODO: 警告 - 如果没有设置 id 字段,此方法将不起作用 if (!(object instanceof Person)) { 返回假; } 其他人=(人)对象; if ((this.prsPtyId == null && other.prsPtyId != null) || (this.prsPtyId != null && !this.prsPtyId.equals(other.prsPtyId))) { 返回假; } 返回真; } @覆盖 公共字符串 toString() { 返回 "com.martinsolaas.webmarin.jpa.Person[prsPtyId=" + prsPtyId + "]"; } }
/* * 要更改此模板,请选择工具 | 模板 * 并在编辑器中打开模板。 */ 包 com.martinsolaas.webmarin.jpa; 导入 java.io.Serializable; 导入 java.util.List; 导入 javax.persistence.Basic; 导入 javax.persistence.CascadeType; 导入 javax.persistence.Column; 导入 javax.persistence.Entity; 导入 javax.persistence.GeneratedValue; 导入 javax.persistence.GenerationType; 导入 javax.persistence.Id; 导入 javax.persistence.JoinColumn; 导入 javax.persistence.JoinTable; 导入 javax.persistence.ManyToMany; 导入 javax.persistence.MapsId; 导入 javax.persistence.NamedQueries; 导入 javax.persistence.NamedQuery; 导入 javax.persistence.OneToOne; 导入 javax.persistence.Table; /** * * @author jms */ @实体 @Table(名称=“派对”,目录=“webmarin”,模式=“webmarin”) @命名查询({ @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")}) 公共类Party实现Serializable { 私有静态最终长序列版本UID = 1L; @ID @基本(可选=假) @Column(名称=“pty_id”,可为空=假) @GeneratedValue(策略 = GenerationType.IDENTITY) 私人长 ptyId; @基本(可选=假) @Column(name = "comment", nullable = false, length = 2147483647) 私有字符串注释; @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 私人名单partyList; @ManyToMany(mappedBy = "partyList") 私人名单partyList1; @OneToOne(cascade = CascadeType.ALL, mappedBy = "party") 私人的人; @OneToOne(cascade = CascadeType.ALL, mappedBy = "party") 私人公司公司; 公共方(){ } 公共方(长 ptyId){ this.ptyId = ptyId; } 公共方(长 ptyId,字符串注释){ this.ptyId = ptyId; this.comment = 评论; } 公共长 getPtyId() { 返回 ptyId; } 公共无效 setPtyId(长 ptyId){ this.ptyId = ptyId; } 公共字符串 getComment() { 返回评论; } 公共无效setComment(字符串评论){ this.comment = 评论; } 公共列表 getPartyList() { 返回派对列表; } 公共无效setPartyList(列表partyList){ this.partyList = 派对列表; } 公共列表 getPartyList1() { 返回派对列表1; } 公共无效setPartyList1(列出partyList1){ this.partyList1 = 派对列表1; } 公共人员 getPerson() { 返回人; } 公共无效 setPerson(个人){ this.person = 人; } 上市公司 getCompany() { 返回公司; } 公共无效setCompany(公司公司){ this.company = 公司; } @覆盖 公共 int hashCode() { 整数哈希 = 0; hash += (ptyId != null ? ptyId.hashCode() : 0); 返回哈希; } @覆盖 公共布尔等于(对象对象){ // TODO: 警告 - 如果没有设置 id 字段,此方法将不起作用 if (!(object instanceof Party)) { 返回假; } 当事人其他=(当事人)对象; if ((this.ptyId == null && other.ptyId != null) || (this.ptyId != null && !this.ptyId.equals(other.ptyId))) { 返回假; } 返回真; } @覆盖 公共字符串 toString() { 返回 "com.martinsolaas.webmarin.jpa.Party[ptyId=" + ptyId + "]"; } }
最终,这里是模式 SQL
创建序列 webmarin.party_pty_id_seq; 创建表 webmarin.party ( pty_id BIGINT NOT NULL DEFAULT nextval('webmarin.party_pty_id_seq'), 评论文本不为空, 约束 pty_pk 主键 (pty_id) ); 更改序列 webmarin.party_pty_id_seq 由 webmarin.party.pty_id 拥有; 创建表 webmarin.company ( cmp_pty_id BIGINT 非空, 名称 VARCHAR(255) 非空, 约束 cmp_pk 主键 (cmp_pty_id) ); 创建表 webmarin.party_relationship ( parent_pty_id BIGINT NOT NULL, child_pty_id BIGINT NOT NULL, 约束 ptr_pk 主键(parent_pty_id,child_pty_id) ); 创建表 webmarin.person ( prs_pty_id BIGINT 非空, 名称 VARCHAR(255), 手机 VARCHAR(55), 办公电话 VARCHAR(55), 约束 prs_pk 主键 (prs_pty_id) ); ALTER TABLE webmarin.party_relationship 添加约束 parent_party_party_relationship_fk 外键(parent_pty_id) 参考 webmarin.party (pty_id) 删除无操作 更新无动作 不可延期; ALTER TABLE webmarin.party_relationship 添加约束 child_party_party_relationship_fk 外键(child_pty_id) 参考 webmarin.party (pty_id) 删除无操作 更新无动作 不可延期; ALTER TABLE webmarin.person 添加约束 party_person_fk 外键 (prs_pty_id) 参考 webmarin.party (pty_id) 删除无操作 更新无动作 不可延期; ALTER TABLE webmarin.company 添加约束 party_company_fk 外键 (cmp_pty_id) 参考 webmarin.party (pty_id) 删除无操作 更新无动作 不可延期;