简体   繁体   中英

How does hibernate distinguish entity types in native query in case of inheritance. What is the real meaning of clazz_ column?

I have a hierarchy of entities:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
class A {
  @Id
  private Long id;
}

@Entity
@PrimaryKeyJoinColumn(name = "id", referencedColumnName = "id")
class B extends A {
}

And a query which retrieves A entities when record in table B does not exist and B entities in other case. I created JPQL query and it worked perfectly, but query had too high cost at the database side. So I decided to create native query and map it to entities. I was wondering how to let Hibernate know which entity should be returned and I found some solution:

JPA Native Query for Entity with Inheritance

entityManager.createNativeQuery("select a.*, b*, 1 as clazz_, from A a LEFT OUTER JOIN B b on id = a.id where procedure(f)",A.class).getResultList()

It looks like there is a special artificial column to distinguish between types. My JPQL query when translated to SQL also had this column. In above example this column has always value of 1 . In my JPQL query it rather looked like:

case when cim.id is not null then 1 when ci.id is not null then 0 end as clazz_

I can just rewrite this into my native query, but how can I be sure that mapping of values 0 and 1 to given types won't change next time? What if I add another class extending A?

The JoinedSubclassEntityPersister defines an IMPLICIT_DISCRIMINATOR_ALIAS property:

private static final String IMPLICIT_DISCRIMINATOR_ALIAS = "clazz_";

Which is used when you don't specify an explicit discriminator value:

explicitDiscriminatorColumnName = null;
discriminatorAlias = IMPLICIT_DISCRIMINATOR_ALIAS;
discriminatorType = StandardBasicTypes.INTEGER;
try {
    discriminatorValue = persistentClass.getSubclassId();
    discriminatorSQLString = discriminatorValue.toString();
}
catch ( Exception e ) {
    throw new MappingException( "Could not format discriminator value to SQL string", e );
}

The 0 and 1 values come from persistentClass.getSubclassId(); which is assigned by Hibernate at runtime:

public Subclass(PersistentClass superclass) {
    this.superclass = superclass;
    this.subclassId = superclass.nextSubclassId();
}

the RootClass default id being 0 :

@Override
public int getSubclassId() {
    return 0;
}

Because the identifiers are assigned at runtime, it's unclear what will happen if a new subclass is added and it's being loaded prior to some already existing ones, so you are better off setting this value explicitly and bypass the implicit subclass ids:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "discriminator", discriminatorType = DiscriminatorType.INTEGER)
class A {
  @Id
  private Long id;
}

@Entity
@PrimaryKeyJoinColumn(name = "id", referencedColumnName = "id")
@DiscriminatorValue(value = 1)
class B extends A {
}

or even better, specify a STRING discriminator:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "discriminator", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue(value = "A")
class A {
  @Id
  private Long id;
}

@Entity
@PrimaryKeyJoinColumn(name = "id", referencedColumnName = "id")
@DiscriminatorValue(value = "B")
class B extends A {
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM