JPA/Hibernate does not add the where clause or make the join on the discriminator for EAGER fetch on SINGLE_TABLE inheritance. When we use the API em.find(class, key), it retrieves more than one instance (
More than one row with the given identifier was found: 1).
Hibernate 4.2.18 under JPA 2.0, JBOSS A7. Single table inheritance pattern.
DATA_REF_CODE2_TB is a list of code.
Code:
DREFSUJID NUMBER(7,0) No (this is the foreign key used as discriminator)
DREFCODCLE VARCHAR2(6 BYTE) No
DREFCODDESC VARCHAR2(256 BYTE) No
DATA_REF_SUJET_TB is a list of topic.
Code:
DREFSUJID NUMBER(7,0)
DREFSUJDESC VARCHAR2(128 BYTE)
Code:
@Entity
@Table(name = "DATA_REF_CODE2_TB")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DREFSUJID", discriminatorType = DiscriminatorType.INTEGER)
public abstract class DataReferenceCode implements ICodeEntity<String> {
private static final long serialVersionUID = 1L;
@NotNull
@Size(min = 1, max = 6)
@Column(name = "DREFCODCLE", unique = true, nullable = false, length = 6, columnDefinition = "varchar2(6)")
@Id
private String code;
@NotNull
@Digits(integer = 7, fraction = 0)
@Column(name = "DREFSUJID", insertable = false, updatable = false, nullable = false, precision = 7, columnDefinition = "number(7,0)")
private long sujet;
@NotNull
@Size(min = 1, max = 256)
@Column(name = "DREFCODDESC", nullable = false, length = 256, columnDefinition = "varchar2(256)")
private String description;
Code:
@Entity
@DiscriminatorValue("111")
public class CodeRegroupement extends DataReferenceCode {
private static final long serialVersionUID = 1L;
// we have nothing here
}
Code:
public interface ICodeEntity<PK extends Serializable> extends IEntity<PK>, ICode<PK> {
}
Code:
public interface ICode<T extends Serializable> extends Serializable {
T getCode();
void setCode(T code);
String getDescription();
void setDescription(String description);
}
Code:
public interface IEntity<PK extends Serializable> extends Serializable {
// we have nothing here
}
Then we have an entity CodeStatutCanada that it contains an attribute CodeRegroupement codeRegroupement.
Code:
@Entity
@Table(name = "PLSTATUT_CANADA")
public class CodeStatutCanada implements ICodeEntity<String> {
private static final long serialVersionUID = 1L;
@Id
@NotNull
@Size(min = 1, max = 1)
@Column(name = "STCCOD", unique = true, length = 1, nullable = false, columnDefinition = "char(1)")
private String code;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "STCCODNOUV")
private CodeStatutGdeu codeStatutGdeu;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "STCCODRGRSTACAN")
private CodeRegroupement codeRegroupement;
@Size(max = 30)
@Column(name = "STCDSC", length = 30, columnDefinition = "char(30)")
private String description;
....
}
Wen we perform the API entityManager.find(classo, pKey); on the entity CodeStatutCanada, it retrieve 2 records instead of one because the discriminator value is not involved into the request. Here the generated output by Hibernate.
Code:
select
codestatut0_.STCCOD as STCCOD147_1_,
codestatut0_.STCCODRGRSTACAN as STCCODRG3_147_1_,
codestatut0_.STCCODNOUV as STCCODNOUV147_1_,
codestatut0_.STCDSC as STCDSC147_1_,
coderegrou1_.DREFCODCLE as DREFCODCLE122_0_,
coderegrou1_.DREFCODDESC as DREFCODD3_122_0_,
coderegrou1_.DREFSUJID as DREFSUJID122_0_
from
SAGE.PLSTATUT_CANADA codestatut0_
left outer join
SAGE.DATA_REF_CODE2_TB coderegrou1_
on codestatut0_.STCCODRGRSTACAN=coderegrou1_.DREFCODCLE
where
codestatut0_.STCCOD=?
The problem is related to the data as we have more than one value for DREFCODCLE. In fact, our primary key is a compound key made of DREFCODCLE + DREFSUJID.
Then, the question is: Is there a way to force the query to have the discriminator value involved into the query ?
Using @DiscriminatorOptions(force = true) does not help neither ! (no JPA compliant - Hibernate specific)