Monday, December 4, 2017

Make Hibernate discriminator value use bind variable instead of literal

Leave a Comment

When using the @DiscriminatorColumn on a class and @DiscriminatorValue on subclasses, the SQL that Hibernate generates uses the discriminator value as a literal for the clause involving the discriminator column.

Example:

@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "PART_TYPE") @Table(name = "NAME") public class NamePartEntity implements Comparable<NamePartEntity> {   // Stuff }  @Entity @DiscriminatorValue(value = "GIV") public class GivenNameEntity extends NamePartEntity {   // stuff } 

If I create a simple criteria query with no criteria except the class, I would get SQL generated like such:

select this_.person_id as y0_ from name this_ where this_.part_type='GIV' 

This isn't so bad until you have a handful of discriminator values and the table might be selected from multiple times, such that a query like the below:

SELECT this_.person_id AS y0_ FROM name this_ WHERE this_.part_type='FAM' AND this_.value_u    =:8 AND this_.tenant_id  =:9 AND this_.person_id IN   (SELECT this_.person_id AS y0_   FROM name this_   WHERE this_.part_type='GIV'   AND this_.value_u    =:10   AND this_.tenant_id  =:11   AND this_.person_id IN     (SELECT this_.person_id AS y0_     FROM name this_     WHERE this_.part_type='GIV'     AND this_.value_u    =:12     AND this_.tenant_id  =:13     AND this_.person_id IN       (SELECT this_.person_id AS y0_       FROM name this_       WHERE this_.part_type='PFX'       AND this_.value_u    =:14       AND this_.tenant_id  =:15       )     )   ) 

could have a ton of different SQL ids and execution plans based on the literals ('FAM', 'GIV', 'PFX' in this case but they could be different and in different orders). However, if bind variables were used in place of those discriminator value literals, it would be the same sql id and have the same execution plan.

So, is it possible to have Hibernate use the discriminator column/value annotations in such a way that bind variables are used instead of literals? I know it would be possible to rewrite my entities in such a way to avoid this but I wanted to see if I could get the bind variable functionality with the existing annotations in some way.

Alternatively, is there a way I can still use my extended classes without using discriminator values? If I try that and have the @Entity annotation on each extended class, it complains about missing the discriminator type even when there are no discriminator annotations.

2 Answers

Answers 1

No, it is not possible to get it out of the box.

The closest workaround that comes to my mind is to select from the base class and explicitly filter by subclass:

entityManager.createQuery("select gne from NamePartEntity gne where type(gne) = :subclass")     .setParameter("subclass", GivenNameEntity.class)     .getResultList(); 

Answers 2

Alternatively, is there a way I can still use my extended classes without using discriminator values? If I try that and have the @Entity annotation on each extended class, it complains about missing the discriminator type even when there are no discriminator annotations

That is because of the InheritanceType.SINGLE_TABLE strategy you've used. You could always try to use other strategies, like InheritanceType.JOINED, depending upon what you query for most often.

On another note, Doesn't having this many types of Names per-se an indicator that you must have types as a relation and not a Sub-type?

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment