Home > Net >  search in inheritance entities by criteria
search in inheritance entities by criteria

Time:06-27

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.

  • Related