Postgresql和Eclipselink的Netbeans代码 - 识别关系问题

时间:2010-08-29 21:57:08

标签: postgresql orm netbeans eclipselink jpa-2.0

我有以下数据库表:

  • party,pk“pty_id”连接到生成pk值的序列。
  • 与party.pty_id的识别关系中包含fpk“prs_pty_id”的人。
  • 公司......目前没有涉及,但显然这是一种超级类设置,它可能已经在postgresql中使用子类化机制实现,但那是另一天。

因此,我使用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;

1 个答案:

答案 0 :(得分:0)

JPA 2.0大大改进了对派生标识符的支持,其中IdMapsId注释(现在应该首选它们)可以在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;
    ...
}

参考