Question

I am mapping a legacy database, one table of which maps naturally to an inheritance hierarchy using the SINGLE_TABLE mapping using a discriminator column. The problem is that there are a huge number of discriminator values! (Also, new ones are occasionally added and the app should automatically pick them up in polymorphic queries). From the point of view of my app, I would like to treat the vast majority of these different types identically (i.e., just map them to the base class in the inheritance hierarchy). However, for a handful, I would like to map to a specific sub-class. The problem is that JPA seems to require that I provide a single specific @DiscriminatorValue on the base class (or otherwise it generates a default one).

To be concrete:

@Entity
@Table("products")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "product_type")
@DiscriminatorValue( *anything not specified elsewhere!* )
public class Product {
    ...
    public double calculateMarkup() { ... default impl ... }
}
@Entity
@DiscriminatorValue("ProductA")
public class ProductA extends Product {
    ...
    @Override public double calculateMarkup() { ... specific impl ... }
}

Is there any way to map this elegantly in JPA (or with Hibernate 3.3-specific extensions)? The only solution I can come with is to abandon inheritance and map the column as a normal field that internally does a switch on that value for the special cases, but that feels unnatural and a little dirty.

Was it helpful?

Solution

Is there any way to map this elegantly in JPA

No, not that I know of. If the problem is caused on the data layer (i.e. data or database) I'd try to solve it on that layer. Try either of the two below approaches:

  • create a view in the database that is identical to the table except that "anything not specified elsewhere" is mapped* to the default discriminator
  • write an on-insert/update trigger on the Product table that fixes the discriminator values of each reacord*.

*Oracle for example provides DECODE to map values from range A to range B if-then-else-like.

OTHER TIPS

I resolved same problem using @DiscriminatorFormula (http://lauraliparulo.altervista.org/hibernate-inheritance/). The discriminator formula returns

CASE WHEN (product_type!='ProductA') THEN 'LEGACY'
ELSE product_type

and Product entity has @DiscriminatorValue('LEGACY')

Look into using a @ClassExtractor: http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Entities/Inheritance#Example:_Using_ClassExtractor_do_define_inheritance

Something like

public class ProductExtractor implements ClassExtractor {
    public void extractClassFromRow(Record row, Session session) {
        if (row.get("product_type").equals("ProductA")) {
            return ProductA.class;
        } 
        return Product.class;
    }
}

then write customizers for your classes and annotate with them.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top