2013-03-28 156 views
9

我有一個包含oracle數據庫中的客戶數據的表。下面是一個簡化的定義:具有空值的JPA複合主鍵

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

此表的主鍵是(CUSTOMER_ID, SOURCE_SYSTEM)

該表有許多行,其中SOURCE_SYSTEM爲空。在數據庫級別,沒有問題,但是當我嘗試訪問任何通過JPA實體這些行的,它會導致一些問題:

1:使用em.find()用空SOURCE_SYSTEM總是導致中讀取行返回null。

2:使用em.merge()到UPSERT一排空SOURCE_SYSTEM成功,如果記錄不存在於表中,但在後續的更新失敗,因爲合併總是導致插入正在運行。

3:使用em.createQuery()明確查詢與空行導致以下異常:

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

不幸的是,「主鍵不能包含空」似乎相當決賽。我無法找到有關此錯誤的解決方法的太多信息,這看起來好像沒有解決方案。

問題:我想知道如果任何人有任何基於Java代碼的解決方案不涉及更改數據庫。我目前的解決方法是使用ROW_ID作爲表中的@Id,但這意味着我不能再使用em.merge()em.find()

這裏是我的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

你爲什麼使用null作爲customer_id?它看起來像應該使用排序的東西,如果它不爲空,應該允許source_system字段爲空。您可以嘗試指定要使用的驗證,如http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_primarykey.htm中所述,但我不確定爲什麼您的操作不起作用。您正在映射customer_id字段兩次,因此請確保您正確地設置了這兩個字段。 – Chris

+0

還打開日誌記錄以查看映射或生成的SQL是否存在問題。對空字段的查詢通常必須略有不同,這可能不會發生,因爲它的pk檢查。 HTTP://wiki.eclipse。org/EclipseLink/Examples/JPA/Logging描述了Eclipselink日誌記錄 – Chris

+0

'CUSTOMER_ID'永遠不會爲空,並且在數據庫中的類和NOT NULL標記爲'nullable = false',但它不基於一個序列。 很可能''em.find()'的sql是用'SOURCE_SYSTEM ='''生成的,而不是'SOURCE_SYSTEM IS NULL',這就是爲什麼記錄沒有被正確返回的原因。 –

回答

0

主鍵不能包含空(在JPA或數據庫)。使用不同的值,例如「」或「」。

customer_id是否是唯一的?如果是這樣,那麼只需從Id中刪除sourceSystem。

否則,您可以嘗試記錄一個錯誤以支持添加空id。

+0

'CUSTOMER_ID'不是唯一的,我不能對錶格進行更改,因爲它已被其他應用程序使用。不幸的是,[Oracle將空字符串視爲空值](http://www.techonthenet.com/oracle/questions/empty_null.php),而且,我無法更改表中現有的空值以適合我自己的需求,因爲它會影響當前期望'SOURCE_SYSTEM'中有空值的任何其他應用程序。 –