2013-03-28 20 views
9

Ho una tabella contenente i dati del cliente in un database Oracle. Ecco una definizione semplificata:Chiave primaria composita JPA con valore null

CUSTOMER (CUSTOMER_ID NUMBER NOT NULL, 
      SOURCE_SYSTEM VARCHAR2(30), 
      FULL_NAME VARCHAR2(360), 
      PHONE_NUMBER VARCHAR2(240) 
     ) 

La chiave primaria per questa tabella è (CUSTOMER_ID, SOURCE_SYSTEM).

La tabella presenta numerose righe per le quali SOURCE_SYSTEM è nullo. A livello di database, non vi è alcun problema, tuttavia quando provo ad accedere a una di queste righe tramite JPA Entity, provoca una serie di problemi:

1: L'utilizzo di em.find() per recuperare una riga con un valore SOURCE_SYSTEM nullo risulta sempre in viene restituito un valore nullo.

2: L'utilizzo di em.merge() per eseguire una riga con un valore vuoto SOURCE_SYSTEM ha esito positivo se il record non esiste nella tabella, ma non riesce negli aggiornamenti successivi perché l'unione SEMPRE determina l'esecuzione di un inserto.

3: Utilizzo em.createQuery() per interrogare in modo esplicito per una riga con un null provoca la seguente eccezione:

Exception [EclipseLink-6044] (Eclipse Persistence Services - 2.3.1.v20111018-r10243): 
    org.eclipse.persistence.exceptions.QueryException 
Exception Description: The primary key read from the row [ArrayRecord(
CUSTOMER.CUSTOMER_ID => 1 
CUSTOMER.FULL_NAME => GUY PERSON 
CUSTOMER.PHONE_NUMBER => 555-555-1234 
CUSTOMER.SOURCE_SYSTEM => null)] during the execution of the query was detected to be null. 
    Primary keys must not contain null. 
Query: ReadAllQuery(referenceClass=Customer sql="SELECT CUSTOMER_ID, FULL_NAME, PHONE_NUMBER, SOURCE_SYSTEM FROM CUSTOMER WHERE ((CUSTOMER_ID = ?) AND (SOURCE_SYSTEM IS NULL))") 

Purtroppo, "chiavi primarie non devono contenere nulla" sembra abbastanza finale. Non sono riuscito a trovare troppe informazioni su soluzioni alternative per questo errore, il che fa sembrare che non ci sia alcuna soluzione.

LA QUESTIONE: Vorrei sapere se qualcuno ha qualche Java soluzione basata sul codice che non comportano apportare modifiche al database. La mia soluzione attuale consiste nell'utilizzare ROW_ID come @Id della tabella, ma ciò significa che non è più possibile utilizzare em.merge() o em.find().

Qui sono le mie classi Java:

Customer.java:

@Entity 
@Table(name = "CUSTOMER") 
public class Customer implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @EmbeddedId 
    private Customer_Id key; 

    @Column(name = "CUSTOMER_ID", nullable = false, insertable = false, updatable = false) 
    private Long customerId; 
    @Column(name = "SOURCE_SYSTEM", length = 30, insertable = false, updatable = false) 
    private String sourceSystem; 

    @Column(name = "FULL_NAME", length = 360) 
    private String fullName; 
    @Column(name = "PHONE_NUMBER", length = 240) 
    private String phoneNumber; 

    //Setters, Getters, etc 
    ... 
} 

Customer_Id.java

@Embeddable 
public class Customer_Id implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Column(name = "CUSTOMER_ID", nullable = false) 
    private Long customerId; 
    @Column(name = "SOURCE_SYSTEM", length = 30) 
    private String sourceSystem; 

    //Setters, Getters, etc 
    ... 
} 
+0

Perché stai utilizzando null per customer_id? Sembra qualcosa che dovrebbe usare il sequenziamento e, se non è nullo, dovrebbe consentire al campo source_system di essere nullo. Puoi provare a specificare la convalida da utilizzare come descritto qui http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_primarykey.htm ma non sono sicuro del motivo per cui ciò che hai non funzionerebbe. Stai mappando il campo customer_id due volte, quindi assicurati di aver impostato correttamente entrambi – Chris

+0

Inoltre attiva la registrazione per vedere se ci sono problemi con i tuoi mapping o l'SQL che viene generato. Le query per i campi Null in genere devono essere leggermente diverse che potrebbero non verificarsi a seguito di un controllo pk. http: //wiki.eclipse.org/EclipseLink/Examples/JPA/Logging descrive la registrazione Eclipselink – Chris

+0

'CUSTOMER_ID' non sarà mai nullo, ed è marcato come' nullable = false' nella classe e 'NOT NULL' nel database, sebbene non sia basato su una sequenza. È molto probabile che sql per 'em.find()' venga generato con 'SOURCE_SYSTEM = ''' invece di 'SOURCE_SYSTEM IS NULL', motivo per cui il record non viene restituito correttamente. –

risposta

0

chiavi primarie non possono contenere null (in JPA o in banche dati). Utilizzare un valore diverso come "" o "".

L'ID cliente è univoco? se è così basta rimuovere il sourceSystem dall'Id.

In caso contrario, è possibile provare a registrare un errore per aggiungere il supporto per gli ID nulli.

+0

'CUSTOMER_ID' non è univoco, e io non è possibile apportare modifiche alla tabella poiché è già utilizzata da altre applicazioni. Sfortunatamente, [Oracle visualizza la stringa vuota come valore nullo] (http://www.techonthenet.com/oracle/questions/empty_null.php), e, non posso modificare i valori nulli esistenti nella tabella per adattarli le mie esigenze personali poiché interesserebbe qualsiasi altra applicazione che al momento prevede un valore nullo in "SOURCE_SYSTEM". –