I have a generic Database structure which can store several user-defined records. For example, the main table is RECORD and the columns are STRING01, STRING02, […], NUM01, NUM02 etc.
I know this is a bit weird, but it has advantages as well as disadvantages. However, this structure exists and can’t be changed. Now I want to create some JPA classes.
First, I created an abstract class RECORD as follows (the Annotations are placed on the gettersthe example is just simplified):
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="TYPE", discriminatorType=DiscriminatorType.STRING)
public abstract class Record {
@Id
private long id;
@Column(name="STRING01")
private String string01;
@Column(name="STRING02")
private String string02;
@Column(name="NUM01")
private BigDecimal num01;
}
Then, I created specific classes inherited from RECORD:
@Entity
@DiscriminatorValue("Person")
public class Person extends Record {
@Transient
public String getFirstName() {
return getString01();
}
public void setFirstName(String name) {
setString01(name);
}
@Transient
public BigDecimal getWeight() {
return getNum01();
}
public void setWeight(BigDecimal weight) {
setNum01(weight);
}
}
This works fine, as I can query RECORD for a PERSON’s primary key (via EntityManager.find()) and get a Result as instance of PERSON. I can query for FirstName and Weight without having to know the generic column names.
However, if I write my own JPA Query like SELECT p FROM Person p WHERE p.firstName = 'Michael', it fails. firstName is transient, and here I have to use the generic name string01.
Is there some way of overriding the base class’ attribute name in JPA? Maybe there’s a vendor-specific solution (I’m using EclipseLink)?
You can try and map multiple attributes to the same column.
The additional attribute would then be annotated with
@Column( name = "column name", insertable = false, updatable = false, nullable = false ).Alternatively, you might be able to replace/enhance the JPQL resolver in order to internally map
p.firstNametop.string01, but that would be EclipseLink specific, and I don’t really know if that’s even possible. Take this as just a hint what to look for.