Situazione
Ho Un'entità con DiscriminatorColumn
, configurato per la tavola ereditarietà singola:DiscriminatorColumn come parte della chiave primaria/id
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="TYPE")
public class ContainerAssignment{
...
}
'ContainerAssignment' ha un riferimento a un'altra entità:
@JoinColumn(name="CONTAINER_ID")
private Container container;
Un contenitore può avere uno ContainerAssignment
di ciascun TIPO. Ciò significa che la chiave primaria della tabella ContainerAssignment
è definita dallo CONTAINER_ID
e dallo TYPE
.
ContainerAssignment
ha alcune sottoclassi, ad es.
@Entity
@DiscriminatorValue("SOME_TYPE")
public class SomeTypeOfContainerAssignment extends ContainerAssignment{
...
}
Ci sarà solo una singola SomeTypeOfContainerAssignment
istanza per un dato CONTAINER_ID
.
Problema
Se io definisco l'APP @Id
come solo il contenitore sul tavolo ContainerAssignment, posso fare entityManager.find(SomeTypeOfContainerAssignment.class, containerId)
, che è grande. Questo esegue qualcosa sulla falsariga di SELECT * FROM CONTAINER_ASSIGNMENT WHERE CONTAINER_ID = 1 AND TYPE = 'SOME_TYPE';
. Sa che ha bisogno del controllo TYPE qui, a causa dell'annotazione @DiscriminatorValue("SOME_TYPE")
sull'entità.
Tuttavia, ciò significa che i riferimenti posteriori da Container a ContainerAssignment si interrompono poiché Container non è realmente la chiave primaria. Ad esempio, se Container ha un @OneToOne(mappedBy=container) private SomeTypeOfContainerAssignment assignment;
, quando leggi in un contenitore, leggerà nell'assegnazione qualcosa come SELECT * FROM CONTAINER_ASSIGNMENT WHERE CONTAINER_ID = 1;
, senza il controllo del tipo. Questo dà tutti i compiti per un contenitore, e poi ne prende uno a caso, potenzialmente del tipo sbagliato, nel qual caso genera un'eccezione.
Se invece definisco JPA @Id
di ContainerAssignment come un ID composito utilizzando container e tipo, i riferimenti alle sottoclassi di ContainerAssignment funzionano correttamente.
Tuttavia, non posso fare entityManager.find(SomeTypeOfContainerAssignment.class, containerId)
, perché containerId non è l'id. Devo fare entityManager.find(SomeTypeOfContainerAssignment.class, new MyPk(containerId, "SOME_TYPE"))
, che sembra sfidare il punto di @DiscriminatorValue("SOME_TYPE")
. Potrei anche usare una singola Entità ContainerAssignment se devo specificare il tipo su find comunque.
Domanda
C'è un modo per avere i riferimenti di lavoro a sottoclassi di una singola entità ereditarietà delle tabelle in cui la chiave primaria sul tavolo è composto per la colonna discriminatore, pur essendo anche in grado di EntityManager.find
semplicemente il parte (i) della chiave primaria che non sono il discriminatore?
Grazie per la tua risposta, ma in realtà non risolve la domanda - c'è un modo per mettere il tipo 'DiscriminatorColumn' all'interno del PK? Sono d'accordo che un PK artificiale è la scelta migliore, ma in molti sistemi non possiamo controllare lo schema e avere a che fare con PK compositi. –
Notate anche che MAI usare chiavi primarie composite è un anti-pattern, secondo il libro di Bill Karwin. – atorres