I have root entity:
@Entity
@DiscriminatorValue("MORAL")
public class MoralEntity {
private static final long serialVersionUID = 1L;
@Id
private String internalId;
@OneToOne(cascade = CascadeType.ALL, optional = true)
@JoinColumn(name = "fk_partner", nullable = true, updatable = true)
private PartnerEntity partner;
}
which have relation to parent entity:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "pType", discriminatorType = DiscriminatorType.STRING)
public class PartnerEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private String internalId;
@Column(insertable = false, updatable = false)
private String pType;
}
And there is child entities:
@Entity
@DiscriminatorValue("E1")
public class Entity1 extends PartnerEntity {
private static final long serialVersionUID = 1L;
@Embedded
private CategoryEntity category;
}
@Entity
@DiscriminatorValue("E2")
public class Entity2 extends PartnerEntity {
private static final long serialVersionUID = 1L;
@Embedded
private CategoryEntity category;
}
@Entity
@DiscriminatorValue("E3")
public class Entity3 extends PartnerEntity {
private static final long serialVersionUID = 1L;
}
I want to search all MoralEntity where partner.category.code = "ABC".
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<MoralEntity> query = cb.createQuery(MoralEntity.class);
Root<MoralEntity> root = query.from(MoralEntity.class);
Join<MoralEntity, PartnerEntity> moralPartnerJoin = root.join("partner");
CodePudding user response:
Because category is not a field of PartnerEntity
, you
cannot search that field directly, you need first a join
with the other entities.
This query should work:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<MoralEntity> query = cb.createQuery( MoralEntity.class );
Root<MoralEntity> root = query.from( MoralEntity.class );
Join<MoralEntity, PartnerEntity> partnerJoin = root
.join( "partner" );
// OPTIONAL: This will remove all Entity3 entries
partnerJoin.on( partnerJoin.type().in( Entity1.class, Entity2.class ) );
Path<Object> code1 = cb.treat( partnerJoin, Entity1.class )
.get( "category" ).get( "code" );
Predicate p1 = cb.equal( code1, "ABC" );
Path<Object> code2 = cb.treat( partnerJoin, Entity2.class )
.get( "category" ).get( "code" );
Predicate p2 = cb.equal( code2, "ABC" );
query.where( cb.or( p1, p2 ) );
List<MoralEntity> resultList = em.createQuery( query ).getResultList();
But, this criteria will generate a SQL query that uses three joins with PartnerEntity
:
select
ormreactiv0_.internalId as internal1_0_,
ormreactiv0_.fk_partner as fk_partn2_0_
from
Moral ormreactiv0_
inner join
Partner ormreactiv1_
on ormreactiv0_.fk_partner=ormreactiv1_.internalId
and (
ormreactiv1_.pType in (?, ?)
)
inner join
Partner ormreactiv2_
on ormreactiv0_.fk_partner=ormreactiv2_.internalId
inner join
Partner ormreactiv3_
on ormreactiv0_.fk_partner=ormreactiv3_.internalId
where
ormreactiv2_.code=?
or ormreactiv3_.code=?
If this causes performance issues, I would consider moving the category
field to the super class PartnerEntity
or use a native query.