Situation
I have an Entity with a DiscriminatorColumn
, configured for single table inheritance:
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="TYPE")
public class ContainerAssignment{
...
}
'ContainerAssignment' has a reference to another Entity:
@JoinColumn(name="CONTAINER_ID")
private Container container;
A container may have one ContainerAssignment
of each TYPE. This means that the primary key of the ContainerAssignment
table is defined by the CONTAINER_ID
and the TYPE
.
ContainerAssignment
has some subclasses e.g.
@Entity
@DiscriminatorValue("SOME_TYPE")
public class SomeTypeOfContainerAssignment extends ContainerAssignment{
...
}
There will only be a single SomeTypeOfContainerAssignment
instance for a given CONTAINER_ID
.
Problem
If I define the JPA @Id
as just the Container on the ContainerAssignment table, I can do entityManager.find(SomeTypeOfContainerAssignment.class, containerId)
, which is great. This runs something along the lines of SELECT * FROM CONTAINER_ASSIGNMENT WHERE CONTAINER_ID = 1 AND TYPE = 'SOME_TYPE';
. It knows it needs the TYPE check in here, because of the @DiscriminatorValue("SOME_TYPE")
annotation on the Entity.
However, this means that the back references from Container to ContainerAssignment breaks as Container is not really the primary key. For example, if Container has a @OneToOne(mappedBy=container) private SomeTypeOfContainerAssignment assignment;
, when you read in a container, it will read in the assignment by something like SELECT * FROM CONTAINER_ASSIGNMENT WHERE CONTAINER_ID = 1;
, without the type checking. This gives it all assignments for a container, and then it picks one seemingly at random, potentially of the wrong type, in which case, it throws an exception.
If instead, I define the JPA @Id
of ContainerAssignment as a composite id using container and type, references to the sub-classes of ContainerAssignment work fine.
However, I cannot do entityManager.find(SomeTypeOfContainerAssignment.class, containerId)
, because containerId is not the id. I have to do entityManager.find(SomeTypeOfContainerAssignment.class, new MyPk(containerId, "SOME_TYPE"))
, which seems to defeate the point of @DiscriminatorValue("SOME_TYPE")
. I might as well just use a single ContainerAssignment Entity if I have to specify type on find anyway.
Question
Is there a way to have working references to sub-classes of a single table inheritance Entity where the primary key on the table is composite on the discriminator column, whilst also being able to EntityManager.find
by just the part(s) of the primary key which are not the discriminator?
DiscriminatorColumn
kinda inside the PK? I agree that an artificial PK is the best choice, but in many systems we can't control the schema and have to deal with composite PKs. – Piroshki