2009-09-12 12 views
19

Ho un problema con il mio modello di dominio jpa. Sto solo cercando di giocare con una semplice ereditarietà per la quale io uso una semplice classe base Person e una sottoclasse Customer. Secondo la documentazione ufficiale (sia JPA che EclipseLink) ho solo bisogno dell'attributo ID/colonna nella classe base. Ma quando eseguo i miei test, ricevo sempre un errore che mi dice che il cliente non ha IDI?L'ereditarietà JPA richiede l'ID nella sottoclasse

Per prima cosa ho pensato che il problema si trova nella visibilità dell'attributo id, perché era privato in primo luogo. Ma anche dopo averlo modificato in protetto (quindi la sottoclasse ha accesso diretto) non funziona.

Persona:

@Entity @Table(name="Persons") 
@Inheritance(strategy = InheritanceType.JOINED) 
@DiscriminatorColumn(name = "TYPE") 
public class Person { 

    @Id 
    @GeneratedValue 
    protected int id; 
    @Column(nullable = false) 
    protected String firstName; 
    @Column(nullable = false) 
    protected String lastName; 

clienti:

@Entity @Table(name = "Customers") 
@DiscriminatorValue("C") 
public class Customer extends Person { 

    //no id needed here 

io sono a corto di idee e risorse da guardare. Dovrebbe essere un problema piuttosto semplice, ma io non lo vedo.

+0

Ho un problema simile. Credo che sia legato a Eclipse.I miei strumenti di sviluppo JBoss lamentano l'assenza di ID su un'entità derivata, ma Maven la compila senza lamentarsi. – Mats

risposta

25

ho risolto io stesso con la creazione di un MappedSuperclass

@MappedSuperclass 
public abstract class EntityBase{ 
    @Id 
    @GeneratedValue 
    private int id; 

    ...setter/getter 
} 

Tutte le entità sono ereditando da questa classe. Mi sto ancora chiedendo perché i tutorial non lo menzionino, ma forse migliora con le implementazioni di JPA 2.

+2

+1. Credo che questa sia la risposta corretta alla tua domanda specifica. –

+0

Grazie per il commento. Non ne ero ancora sicuro. – lostiniceland

+1

A questo punto il documento oracle riporta la notazione "MappedSuperclass": https://docs.oracle.com/javaee/7/tutorial/doc/persistence-intro002.htm. È definitivamente il modo giusto :) –

3

APP conosce due modi diversi per applicare l'ereditarietà:

  • eredità tavolo Iscritto
  • Tavolo unico eredità

Con tavolo ereditarietà singola avrete bisogno di una colonna discriminatore per distinguere tra le file in la tavola.

Con l'ereditarietà della tabella unita, ogni classe ottiene la propria tabella in modo che non sia necessaria alcuna colonna di discriminazione.

Penso che il tuo problema sia che hai combinato i due concetti. Quindi, o:

  • definire le colonne discriminatore e usare `InheritanceType.SINGLE_TABLE` e non lo fanno uso` @ table` su sottoclassi
  • o utilizzare `InheritanceType.JOINED` ma non lo fanno specificano la colonna e i valori discriminatori!
+1

Ho provato, ma ancora lo stesso problema. Inoltre, secondo http://en.wikibooks.org/wiki/Java_Persistence/Inheritance#Joined.2C_Multiple_Table_Inheritance puoi usare il discriminatore – lostiniceland

4

So che questo è vecchio ma comunque valido. Ho incontrato lo stesso problema. Tuttavia, @MappedSuperClass non è uguale a una tabella di ereditarietà singola. MappedSuperClass creerà tabelle separate per ciascuna sottoclasse (come ho capito)

Non so esattamente perché, ma quando ho solo una classe ereditata non ho avuto problemi. Tuttavia, una volta aggiunto il secondo e il terzo, ho ricevuto lo stesso errore. Quando ho specificato l'annotazione @Id nella tabella figlio, ha iniziato a funzionare di nuovo.

Il mio layout era semplice, informazioni di contatto per aziende, agenti e clienti.

Parent

Tabella:

... 
@Entity 
@Inheritance(strategy= InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="USER_TYPE", length=10, discriminatorType= DiscriminatorType.STRING) 
@Table(name="CONTACTS") 
public abstract class AbstractContact implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    protected Long id; 
    @Column (length=10, nullable=false) 
    protected String mapType; 
    @Column (length=120, nullable=false) 
    protected String mapValue; 
... 

Agente Contatti

@Entity 
@DiscriminatorValue("Agent") 
public class AgentContact extends AbstractContact implements Serializable { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    protected Long id; 
    @ManyToOne(fetch=FetchType.LAZY) 
    @JoinColumn(name="USER_ID") 
    protected Agents agent; 
} 

Azienda Contatti:

@Entity 
@DiscriminatorValue("Company") 
public class CompanyContact extends AbstractContact implements Serializable { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    protected Long id; 
    @ManyToOne(fetch=FetchType.LAZY) 
    @JoinColumn(name="USER_ID") 
    protected Companies company; 

} 

client Contatti:

@Entity 
@DiscriminatorValue("Client") 
public class ClientContact extends AbstractContact implements Serializable { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    protected Long id; 
    //Client table not built yet so... no mapping 
} 

La tabella dei clienti non è ancora stata creata, quindi non ci sono informazioni di mappatura, ma ottieni il punto.

Volevo condividere la descrizione di MySQL, ma il prompt dei comandi di Windows è troppo inutile da tagliare/copiare/incollare! In sostanza, la sua: ID (int pri) USER_TYPE (VARCHAR (10)) USER_ID (INT) maptype (VARCHAR (10)) MAPVALUE (VARCHAR (120))

devo ancora installare tutti i test, ma finora sembra buono (temo che se aspetto fino a dopo aver fatto tutti i test dimenticherò di postare questo)

9

Ho avuto esattamente lo stesso problema. Per sottoclasse mi è stato sempre:

Entity class [...] has no primary key specified. It should define either an @Id, @EmbeddedId or an @IdClass.

Nel mio caso si è scoperto che ho dimenticato di aggiungere la mia classe radici in persistence.xml.

assicurarsi di avere sia Persona e clienti definiti in:

<persistence> 
    <persistence-unit> 
    ... 
    <class>package.Person</class> 
    <class>package.Customer</class> 
    ... 
    </persistence-unit> 
</persistence> 
0

Ci può essere un altro motivo per questo errore quando si utilizza Glassfish/EclipseLink: EclipseLink < 2.6.0 ha un nasty bug causano classi con le espressioni lambda in esso da ignorare. Ciò potrebbe portare a errori confusi, come quello menzionato qui, o altri errori simili (ad esempio, EclipseLink potrebbe dirti che una classe con un'annotazione @Entity non è un'entità).

Glassfish 4.1 include EclipseLink 2.5.x, quindi questo bug (e molti altri) ti morderà se utilizzi Glassfish. Stavo usando questa versione invece di 4.1.1 a causa di un altro bug che rendeva impossibile l'uso della validazione nei servizi web REST. Rimani il più lontano possibile da Glassfish se vuoi mantenere la tua sanità mentale.

0

È possibile ottenere questo tipo di errore quando non si sta generando lo schema del database basato sulle entità. Se questo è il caso:

1 ° - Il tuo superclasse deve sempre avere un @Id

2 ° - La sottoclasse deve avere qualche colonna che identifica la classe estesa (super classe @Id)

3 ° - La soluzione più semplice per il caso presentato sopra sarebbe aggiungere un id di colonna alla tabella di sottoclasse, con il vincolo di chiave esterna corrispondente.

Spero che questo aiuti qualcuno! Pollice in alto!

Problemi correlati