2013-03-28 17 views
9

Mam tabelę zawierającą dane klientów w bazie danych Oracle. Oto uproszczona definicja:Wspólny klucz podstawowy JPA z wartością pustą

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

Klucz podstawowy dla tej tabeli to (CUSTOMER_ID, SOURCE_SYSTEM).

Tabela ma wiele wierszy, dla których SOURCE_SYSTEM ma wartość null. Na poziomie bazy danych nie ma problemu, ale gdy próbuję uzyskać dostęp do dowolnego z tych wierszy za pośrednictwem jednostki JPA, powoduje to szereg problemów:

1: użycie em.find() do pobrania wiersza z wartością zerową SOURCE_SYSTEM zawsze powoduje zwracana jest wartość null.

2: Użycie em.merge() do wstawienia wiersza o wartości zerowej SOURCE_SYSTEM powiedzie się, jeśli rekord nie istnieje w tabeli, ale kończy się niepowodzeniem w kolejnych aktualizacjach, ponieważ scalenie ZAWSZE powoduje uruchomienie wkładki.

3: Korzystanie em.createQuery() jawnie zapytać o wierszu z pustym powoduje następujący wyjątek:

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))") 

Niestety, „Klucze główne nie może zawierać null” wydaje się dość ostateczna. Nie mogłem znaleźć zbyt wielu informacji na temat obejścia tego błędu, co sprawia, że ​​wydaje się, że nie ma rozwiązania.

KWESTIA: Chciałbym wiedzieć, czy ktoś ma jakieś kodu Java rozwiązanie które nie wymagają wprowadzania zmian do bazy danych. Moje bieżące obejście polega na użyciu ROW_ID jako tabeli @Id, ale oznacza to, że nie mogę już używać em.merge() ani em.find().

Oto moje klasy 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

Dlaczego używasz wartości null dla identyfikatora klienta? Wygląda to na coś, co powinno korzystać z sekwencjonowania, a jeśli nie jest zerowe, powinno pozwolić na to, by pole source_system miało wartość null. Możesz spróbować określić walidację, która ma być używana, jak opisano tutaj http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_primarykey.htm, ale nie jestem pewien, dlaczego to, co zrobiłeś, nie zadziałałoby. Odwzorowujesz pole customer_id dwa razy, więc upewnij się, że obie opcje są poprawne. – Chris

+0

Włącz także logowanie, aby sprawdzić, czy występują problemy z odwzorowaniami lub wygenerowanym SQL. Zapytania dotyczące pól pustych muszą się zasadniczo różnić, co może nie występować od sprawdzenia pk. http: //wiki.eclipse.org/EclipseLink/Examples/JPA/Logging opisuje logowanie Eclipselink – Chris

+0

'CUSTOMER_ID' nigdy nie będzie mieć wartości NULL i jest oznaczone jako" nullable = false "w klasie, a także" NOT NULL "w bazie danych, chociaż nie jest oparte na sekwencja. Jest bardzo prawdopodobne, że sql dla 'em.find()' jest generowany z 'SOURCE_SYSTEM = ''' zamiast 'SOURCE_SYSTEM IS NULL', dlatego rekord nie jest zwracany poprawnie. –

Odpowiedz

0

klucze pierwotne nie mogą zawierać wartości null (w JPA lub w bazach danych). Użyj innej wartości, np. "" Lub "".

Czy adres klienta jest unikatowy? jeśli tak, po prostu usuń sourceSystem z Id.

W przeciwnym razie możesz spróbować zarejestrować błąd, aby dodać obsługę identyfikatorów o wartości null.

+0

'CUSTOMER_ID' nie jest unikalny, a ja nie może wprowadzać zmian w tabeli, ponieważ są już używane przez inne aplikacje. Niestety, [Oracle traktuje pusty ciąg jako wartość pustą] (http://www.techonthenet.com/oracle/questions/empty_null.php), i nie mogę zmienić istniejących wartości pustych w tabeli, aby dopasować moje własne potrzeby, ponieważ wpłynęłoby to na wszelkie inne aplikacje, które obecnie oczekują wartości zerowej w 'SOURCE_SYSTEM'. –

Powiązane problemy