title: Netbeans code for Postgresql and Eclipselink - identifying relation question
body: <p>I have the following database tables:</p>
  
  <ul>
  <li>party, with a pk "pty_id" connected to a sequence for generating pk values.</li>
  <li>person with a fpk "prs_pty_id" in an identifying relation to party.pty_id.</li>
  <li>company ... which is not involved at the moment, but obviously this is kindof sub-superclass setup, and it could probably have been implemented with the subclassing mechanism in postgresql, but that's for another day.</li>
  </ul>
  
  <p>So, I use Netbeans 6.9.1 to generate JPA entity classes and controller/dao code to handle this. It works just nice, I only have to add one annotation to the Party Entity bean: @GeneratedValue(strategy = GenerationType.IDENTITY). This is not needed for the Person entity bean, because it should always have the pk value of the Party that it is connected to.</p>
  
  <p>So here is what I do to create a person: </p>
  
  <pre><code>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()); // &lt;== why do I need to set this ...
  Long partyId = par.getPtyId();
  par.setPerson(per); // &lt;== ... 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());
  </code></pre>
  
  <p>This works just fine. But why do I have to explicitly set the pk of the Person bean? It is in an identifying relationship with the Party. If I skip it, I get</p>
  
  <pre><code>java.lang.IllegalArgumentException: An instance of a null PK has been incorrectly provided for this find operation.
  </code></pre>
  
  <p>in perController.create(per), which is code generated by Netbeans:</p>
  
  <pre><code>EntityManager em = null;
  try {
      em = getEntityManager();
      em.getTransaction().begin();
      Party party = person.getParty();
      if (party != null) {
          party = em.getReference(party.getClass(), party.getPtyId()); // &lt;== Exception thrown here
          person.setParty(party);
      }
      em.persist(person);
      if (party != null) {
          party.setPerson(person);
          party = em.merge(party);
      }
      em.getTransaction().commit();
  </code></pre>
  
  <p>So, I suppose the Netbeans-generated code is not quite tuned for identifying relationships? What's the best way to code this? </p>
  
  <p>Software used: Eclipselink version 2.1.1 Postgresql 8.4 Netbeans 6.9.1 Java/JDK 1.6.0_21</p>
  
  <p>Here are my beans, they're generated by netbeans 6.9.1 from schema, except the @GeneratedValue(strategy = GenerationType.IDENTITY) in Party, which I've added in order to use the serial/sequence pk generation in postgresql.</p>
  
  <pre>
  /*
   * 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 + "]";
      }
  
  }
  
  </pre>
  
  <pre>
  /*
   * 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 + "]";
      }
  
  }
  
  </pre>
  
  <p>Eventually, here is the schema SQL</p>
  
  <pre>
  
  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;
  </pre>