I posted this question before but I am now seeing it in several places and can
produce a test case for it. Here are two related classes (one-to-many) attribute
and attributeType, each with table/class inheritance.


Attribute class:
package ca.BidSpec.emall.categories;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

import ca.BidSpec.emall.commonServices.PrimaryKey;
import ca.BidSpec.emall.persistence.Persistable;

@Entity
@Table(name = "attributes")
@NamedQueries( {
                @NamedQuery(name = "AttributeFXPK", query = "SELECT a FROM
Attribute a WHERE a.id = :primaryKey"),
                @NamedQuery(name = "AttributeFXDescription", query = "SELECT a
FROM Attribute a WHERE a.value = :description ORDER BY a.value") })
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Attribute extends Persistable {

        private AttributeType type;

        private String value = "";

        /*
         * required for persistence
         */
        private Attribute() {
        }

        public Attribute(PrimaryKey pk) {
                this.setPrimaryKey(pk);
        }

        /**
         * @param pk
         *            this objects primary key
         * @param type
         *            this object attribute type
         * @param value
         *            the value for this attribute given it's type
         */
        public Attribute(PrimaryKey pk, AttributeType type, String value) {
                this.setPrimaryKey(pk);
                this.setType(type);
                this.setValue(value);
        }

        @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.REFRESH,
CascadeType.MERGE })
        @JoinColumn(name = "attributeTypeFK")
        public AttributeType getType() {
                return type;
        }

        public void setType(AttributeType type) {
                this.type = type;
        }

        @Basic()
        @Column(name = "value", nullable = false, length = 50)
        public String getValue() {
                return value;
        }

        public void setValue(String value) {
                this.value = value;
        }
}


AttributeType Class
package ca.BidSpec.emall.categories;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

import ca.BidSpec.emall.commonServices.PrimaryKey;
import ca.BidSpec.emall.persistence.Persistable;

@Entity
@Table(name = "attributetype")
@NamedQueries( {
                @NamedQuery(name = "AttributeTypeFXPK", query = "SELECT a FROM
AttributeType a WHERE a.id = :primaryKey"),
                @NamedQuery(name = "AttributeTypeFXDescription", query = "SELECT
a FROM AttributeType a WHERE a.description = :description ORDER BY
a.description") })
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class AttributeType extends Persistable {
        private String description = "";

        /*
         * required for persistence
         */
        private AttributeType() {
        }

        public AttributeType(PrimaryKey pk) {
                this.setPrimaryKey(pk);
        }

        public AttributeType(PrimaryKey pk, String description) {
                this.setPrimaryKey(pk);
                this.setDescription(description);
        }

        @Basic()
        @Column(name = "description", length = 50)
        public String getDescription() {
                return description;
        }

        /*
         * Set this attribute type's description
         */
        public void setDescription(String description) {
                this.description = description;
        }
}

Persistable is my based persistable class of all Entities:

package ca.BidSpec.emall.persistence;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import ca.BidSpec.emall.commonServices.PrimaryKey;

@MappedSuperclass
public abstract class Persistable implements Serializable {

        /**
         * Comment for <code>id</code> This is a persistable objects Primary id
         */

        private String id;

        /**
         * User record last updated
         */

        private Timestamp lastUpdated = new Timestamp((new Date()).getTime());

        /**
         * @return Returns the persistable objects id.
         */
        @Id
        @Column(name = "id")
        protected String getId() {
                return this.id;
        }

        protected void setId(String theId) {
                this.id = theId;
        }

        /**
         * @return this object id in a primary id object
         */
        @Transient
        public PrimaryKey getPrimaryKey() {
                return new PrimaryKey(this.getId());
        }

        /**
         * @param id
         *            The id to set.
         */
        public void setPrimaryKey(PrimaryKey primaryKey) {
                this.setId(primaryKey.getKey());
        }

        /**
         * @return Returns the lastUpdated date for this object. 
         */
        @Basic
        @Temporal(TemporalType.TIMESTAMP)
        @Column(name = "lastUpdated")
        public Timestamp getLastUpdated() {
                return this.lastUpdated;
        }

        public void setLastUpdated(Timestamp lastUpdated) {
                this.lastUpdated = lastUpdated;
        }

        public boolean equals(Object obj) {
                if ((obj != null) && (obj instanceof Persistable)) {
                        if (((Persistable) obj).getId().equals(this.getId())) {
                                return true;
                        }
                }
                return false;
        }

        public int hashCode() {
                return this.getId().hashCode();
        }

Here is the query generated:

16360  TRACE  [main] openjpa.jdbc.SQL - <t 28346522, conn 30686131> executing
prepstmnt 17313093 SELECT t0.id, t0.lastUpdated, t1.id, t1.lastUpdated,
t1.description, t0.value FROM attributes t0 LEFT OUTER JOIN attributetype t1 ON
t0.attributeTypeFK = t1.id WHERE t0.id = ? [params=(String)
111e3a22-728a-86ce-0126-11a7acec229a:0]

It should not be selecting from two tables as it cannot create the object. As I
mentioned before (in the other thread) this causes the looked for object to be
null as if the object was not found. Here is my call statement

                Attribute deleteObj = (Attribute)
categoryFactory.getObjectByPK(Attribute.class,
                                "111e3a22-728a-86ce-0126-11a7acec229a:0"); <-
this ID exists in the table
                assertNotNull(deleteObj); <-- fails here 

getObjectBYPK is 

        public Persistable getObjectByPK(Class<? extends Persistable>
objectTypeBeingSought, String pk) {
                Persistable per = null;
                per = (Persistable)
getEntityManager().find(objectTypeBeingSought, pk);
                return per;
        }

}

I think this may be a bug as I see it in several classes - but frustratingly not
all. Any suggestions

Phill

Reply via email to