Hello.
I've built a test project to evaluate inheritance impacts on JPA/Hibernate persistence.
The java classes at the end of the post give the detailed code.
In the hierarchy, the intermediate abstract entity "device" has a many-to-one association with the entity "brand". It seems that the lazy resolution of the a brand's devices leads to a bad generated SQL query, finding on the device table an attribute of the super class "thing".
Here is the generated request, with the bad column "kind_of_thing" wich is actually a super class table field.
Code:
select
devices0_.brand_code as brand_co3_0_0_,
devices0_.identifier as identifi2_2_0_,
devices0_.identifier as identifi2_5_1_,
devices0_1_.description as descript3_5_1_,
devices0_1_.person_identifier as person_i4_5_1_,
devices0_.brand_code as brand_co3_2_1_,
devices0_.model as model1_2_1_,
devices0_2_.bearer as bearer1_4_1_,
devices0_3_.cpu as cpu1_1_1_,
devices0_.[b][color=#FF0000]kind_of_thing[/color][/b] as kind_of_1_5_1_
from
Device devices0_
inner join
Thing devices0_1_
on devices0_.identifier=devices0_1_.identifier
left outer join
Phone devices0_2_
on devices0_.identifier=devices0_2_.identifier
left outer join
Computer devices0_3_
on devices0_.identifier=devices0_3_.identifier
where
devices0_.brand_code=?
I've done tests with versions 4.3.8.Final, 4.3.10.Final, and 5.0.0.CR1, and the result is the same...
Is there anything wrong in my code, or is it a probable bug ?
Thanks for your help.
Regards.
Code:
package my.tests.jpa.entities;
import javax.persistence.Basic;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "kind_of_thing")
public abstract class Thing {
@Id
private Integer identifier;
@Basic
private String description;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "person_identifier")
private Person owner;
public Integer getIdentifier() {
return identifier;
}
public void setIdentifier(final Integer identifier) {
this.identifier = identifier;
}
public String getDescription() {
return description;
}
public void setDescription(final String description) {
this.description = description;
}
public Person getOwner() {
return owner;
}
public void setOwner(final Person owner) {
this.owner = owner;
}
@Override
public String toString() {
return getClass().getSimpleName() + "[identifier=" + identifier + ", description=" + description + "]";
}
}
Code:
package my.tests.jpa.entities;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PrimaryKeyJoinColumn;
@Entity
@PrimaryKeyJoinColumn(name = "identifier")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Device extends Thing {
@Basic
private String model;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "brand_code")
private Brand brand;
public String getModel() {
return model;
}
public void setModel(final String model) {
this.model = model;
}
public Brand getBrand() {
return brand;
}
public void setBrand(final Brand brand) {
this.brand = brand;
}
@Override
public String toString() {
return super.toString() + "[model=" + model + "]";
}
}
Code:
package my.tests.jpa.entities;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.PrimaryKeyJoinColumn;
@Entity
@DiscriminatorValue("PHONE")
@PrimaryKeyJoinColumn(name = "identifier")
public class Phone extends Device implements Serializable {
private static final long serialVersionUID = 7154346535880588320L;
@Basic
private String bearer;
public String getBearer() {
return bearer;
}
public void setBearer(final String bearer) {
this.bearer = bearer;
}
@Override
public String toString() {
return super.toString() + "[bearer=" + bearer + "]";
}
}
Code:
package my.tests.jpa.entities;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.PrimaryKeyJoinColumn;
@Entity
@DiscriminatorValue("VEHICLE")
@PrimaryKeyJoinColumn(name = "identifier")
public class Vehicle extends Thing implements Serializable {
private static final long serialVersionUID = 7046492255061930015L;
@Basic
private String number;
public String getNumber() {
return number;
}
public void setNumber(final String number) {
this.number = number;
}
@Override
public String toString() {
return super.toString() + "[number=" + number + "]";
}
}
and the DDL...
Code:
DROP INDEX IF EXISTS index_thing_owner CASCADE;
DROP INDEX IF EXISTS index_device_brand CASCADE;
DROP TABLE IF EXISTS person CASCADE;
DROP TABLE IF EXISTS thing CASCADE;
DROP TABLE IF EXISTS vehicle CASCADE;
DROP TABLE IF EXISTS device CASCADE;
DROP TABLE IF EXISTS phone CASCADE;
DROP TABLE IF EXISTS computer CASCADE;
DROP TABLE IF EXISTS brand CASCADE;
CREATE TABLE brand (
code VARCHAR(16) PRIMARY KEY NOT NULL,
name VARCHAR(64) NOT NULL
);
ALTER TABLE brand OWNER TO fifi;
CREATE TABLE person (
identifier INTEGER PRIMARY KEY NOT NULL,
name VARCHAR(64) NOT NULL
);
ALTER TABLE person OWNER TO fifi;
CREATE TABLE thing (
identifier INTEGER PRIMARY KEY NOT NULL,
description VARCHAR(128) NOT NULL,
person_identifier INTEGER NOT NULL,
kind_of_thing VARCHAR(16) NOT NULL,
FOREIGN KEY (person_identifier) REFERENCES person (identifier)
);
ALTER TABLE thing OWNER TO fifi;
CREATE INDEX index_thing_owner ON thing (person_identifier);
CREATE TABLE vehicle (
identifier INTEGER PRIMARY KEY NOT NULL,
number VARCHAR(32) NOT NULL,
FOREIGN KEY (identifier) REFERENCES thing (identifier)
);
ALTER TABLE vehicle OWNER TO fifi;
CREATE TABLE device (
identifier INTEGER PRIMARY KEY NOT NULL,
model VARCHAR(128) NOT NULL,
brand_code VARCHAR(16) NOT NULL,
FOREIGN KEY (identifier) REFERENCES thing (identifier),
FOREIGN KEY (brand_code) REFERENCES brand (code)
);
ALTER TABLE device OWNER TO fifi;
CREATE INDEX index_device_brand ON device (brand_code);
CREATE TABLE phone (
identifier INTEGER PRIMARY KEY NOT NULL,
bearer VARCHAR(32) NOT NULL,
FOREIGN KEY (identifier) REFERENCES device (identifier)
);
ALTER TABLE phone OWNER TO fifi;
CREATE TABLE computer (
identifier INTEGER PRIMARY KEY NOT NULL,
cpu VARCHAR(32) NOT NULL,
FOREIGN KEY (identifier) REFERENCES device (identifier)
);
ALTER TABLE computer OWNER TO fifi;