persistence@glassfish.java.net

Code related to bug - 796 : Self Many-Many Relationship

From: Pramod Gopinath <Pramod.Gopinath_at_Sun.COM>
Date: Mon, 24 Jul 2006 15:07:33 -0700

Hi Guy
  I have some questions that I wanted to clarify with you. I am working
on resolving the glassfish issue :
https://glassfish.dev.java.net/issues/show_bug.cgi?id=796
that deals with a "Self-referencing manytomany relationship".

_/*Problem Description :*/_
I have a very simple entity Customer that has a unidirectional
many-to-many self relationship defined. Sample code that I am using is
attached to this email. In short the relationship is defined as :
@Entity
@Table(name="CUSTOMER")
public class Customer {
...
    @Id
    @Column(name="CUST_ID")
    public Integer getCustomerId() {
        return customerId;
    }

    public void setCustomerId(Integer id) {
        this.customerId = id;
    }
...
    *_at_ManyToMany
    public Collection<Customer> getReportees() {
        return reportees;
    }

    public void setReportees(Collection<Customer> reportees) {
        this.reportees = reportees;
    }
*
} // end of Customer entity

As part of java2db the join table that gets generated is of the form :
/CREATE TABLE CUSTOMER_CUSTOMER (
reportees_CUST_ID NUMBER(10) NOT NULL,
PRIMARY KEY (reportees_CUST_ID))

ALTER TABLE CUSTOMER_CUSTOMER
ADD CONSTRAINT CSTOMERCUSTOMERreporteesCUSTID
FOREIGN KEY (reportees_CUST_ID)
REFERENCES CUSTOMER (CUST_ID)/

This is wrong.

_/*Questions about Code Understanding :*/_
When trying to debug the problem, found that in case of a self
referencing manytomany relationship the source fields are not getting
setup properly as part of the annotation processing. I wanted to find
out from you why is there this check in the code :
glassfish/entity-persistence/src/java/oracle/toplink/essentials/internal/ejb/cmp3/metadata/accessors/CollectionAccessor.processJoinTable(
..)
starting at line 225 :
if (getReferenceDescriptor().hasManyToManyAccessorFor(getJavaClassName())) {
   
defaultSourceFieldName = getReferenceDescriptor().getManyToManyAccessor(getJavaClassName()).getAttributeName();
} else {
   
defaultSourceFieldName = Helper.getShortClassName(getJavaClass().getName());
}

This check is the reason why I do not get the Customer.id field not
added to the many-to-many relationship and hence the bug.
Can you throw more light on this if statement.

Thanks
Pramod




//Copyright (c) 1998, 2004, Oracle Corporation. All rights reserved.
package entity;

import javax.persistence.*;

import java.util.Collection;

@Entity
@Table(name="CUSTOMER")
public class Customer implements java.io.Serializable{

    private Integer customerId;
    private int version;
    private String city;
    private String name;
// private Collection<Order> orders;
    private Collection<Customer> reportees;

    public Customer() {
    }

    //_at_Id(generate=TABLE, generator="CUST_SEQ")
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="USERS_SEQUENCE_GENERATOR")
    @SequenceGenerator(name="USERS_SEQUENCE_GENERATOR",sequenceName="CUSTOMER_CUST_ID_seq")
    @Column(name="CUST_ID")
    public Integer getCustomerId() {
        return customerId;
    }

    public void setCustomerId(Integer id) {
        this.customerId = id;
    }

    @Version
    @Column(name="CUST_VERSION")
    public int getVersion() {
        return version;
    }

    protected void setVersion(int version) {
        this.version = version;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String aCity) {
        this.city = aCity;
    }


    public String getName() {
        return name;
    }

    public void setName(String aName) {
        this.name = aName;
    }

/*
    @OneToMany
    //_at_JoinColumn(name="CUST_ID", referencedColumnName="CUST_ID")
    public Collection<Order> getOrders() {
        return orders;
    }

    public void setOrders(Collection<Order> newValue) {
        this.orders = newValue;
    }

    public void addOrder(Order anOrder) {
        getOrders().add(anOrder);
        anOrder.setCustomer(this);
    }
                             
    public void removeOrder(Order anOrder) {
        getOrders().remove(anOrder);
    }
*/

    @ManyToMany
    public Collection<Customer> getReportees() {
        return reportees;
    }

    public void setReportees(Collection<Customer> reportees) {
        this.reportees = reportees;
    }

/*
    @ManyToMany
    private Collection<Order> getCustOrder() {
        return null;
    }

    private void setCustOrder(Collection<Order> cust) {
    }
*/

}