I have a Client and Affiliate class, inheriting from Person class. Joined inheritance strategy type is being used - each of them sharing primary key with the parent class. As there's no discriminator column we chose to use DescriptorCustomizer and ClassExtractor. But it doesn't really give any idea how it works, also, the code doesnt seem to compile. It would be nice if someone gives a nice example with code snippet for understanding.
According to the mentioned documentation:
If you are mapping to an existing database, and the tables do not have a discriminator column you can still define inheritance using the
@ClassExtractor
annotation or<class-extractor>
element. The class extractor takes a class that implements theClassExtractor
interface. An instance of this class is used to determine the class type to use for a database row. The class extractor must define aextractClassFromRow()
method that takes the databaseRecord
andSession
.
we need to annotate the root entity in a hierarchy with user defined using the class extractor:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@ClassExtractor(PersonClassExtractor.class)
public abstract class Person {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private int age;
// ...
}
Notice that we don't use @Customizer
annotations since as this is not required in case of JOINED
inheritance strategy:
If a class extractor is used with
SINGLE_TABLE
inheritance, the rows of the class type must be able to be filtered in queries. This can be accomplished by setting anonlyInstancesExpression()
orwithAllSubclassesExpression()
for branch classes. These can be set toExpression
objects using aDescriptorCustomizer
.
The class extractor must be able to determine and return the class type from the database row. In general we need a replacement of a discriminator column, i.e.
Suppose that each of inherited entity type in a hierarchy has a column with unique name:
@Entity
public class Client extends Person {
@Column(name = "CLIENT_SPECIFIC")
private String clientSpecific;
// ...
}
@Entity
public class Affiliate extends Person {
@Column(name = "AFFILIATE_SPECIFIC")
private float affiliateSpecific;
// ...
}
then class extractor may look as follows:
public class PersonClassExtractor extends ClassExtractor {
@Override
public Class<?> extractClassFromRow(Record databaseRow, Session session) {
if (databaseRow.containsKey("CLIENT_SPECIFIC")) {
return Client.class;
} else if (databaseRow.containsKey("AFFILIATE_SPECIFIC")) {
return Affiliate.class;
} else {
return Person.class; // this should never happen
}
}
}
List<Person> polymorphicResults = em.createQuery("SELECT p FROM Person p")
.getResultList();
List<Affiliate> concreteResults = em.createQuery("SELECT a FROM Affiliate a")
.getResultList();
List<Client> concreteResults = em.createQuery("SELECT c FROM Client c")
.getResultList();