Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA composite primary key with null value

I have a table containing customer data in an oracle database. Here is a simplified definition:

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

The primary key for this table is (CUSTOMER_ID, SOURCE_SYSTEM).

The table has numerous rows for which SOURCE_SYSTEM is null. At the database level, there is no issue, however when I try to access any of these rows via JPA Entity, it causes a number of issues:

1: Using em.find() to fetch a row with a null SOURCE_SYSTEM always results in a null being returned.

2: Using em.merge() to upsert a row with a null SOURCE_SYSTEM succeeds if the record does not exist in the table, but fails on subsequent updates because the merge ALWAYS results in an insert being run.

3: Using em.createQuery() to explicitly query for a row with a null causes the following exception:

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

Unfortunately, "Primary keys must not contain null" seems pretty final. I was unable to find too much information on workarounds for this error, which makes it seem like there is no solution.

THE QUESTION: I would like to know if anyone has any Java code-based solution that don't involve making changes to the database. My current workaround is to use ROW_ID as the @Id of the table, but this means I can no longer use em.merge() or em.find().

Here are my Java classes:

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
  ...
}
like image 812
Matsu Q. Avatar asked Mar 28 '13 17:03

Matsu Q.


People also ask

What is a composite key in JPA?

2. Composite Primary Keys A composite primary key, also called a composite key, is a combination of two or more columns to form a primary key for a table. In JPA, we have two options to define the composite keys: the @IdClass and @EmbeddedId annotations.

How do I specify a primary key in JPA?

You can specify a primary key as a single primitive, or JDK object type entity field (see "Configuring a JPA Entity Simple Primary Key Field" ). You can specify a composite primary key made up of one or more primitive, or JDK object types using a separate composite primary key class (see "Configuring a JPA Entity Composite Primary Key Class" ).

Can a primary key have a null value?

You would need to employ a UNIQUE constraint instead of a PRIMARY KEY constraint to achieve that. Not? No, primary keys can never have null values! SQL> create table t 2 ( 3 a integer null, b integer null, constraint t_pkg primary key (a, b) 4 ) 5 / Table created.

What is the identity strategy in JPA?

The IDENTITY strategy relies on the database auto-increment column. The database generates the primary key after each insert operation. JPA assigns the primary key value after performing the insert operation or upon transaction commit:


1 Answers

Primary keys cannot contain null (in JPA or in databases). Use a different value such as "" or " ".

Is the customer_id unique? if so then just remove the sourceSystem from the Id.

Otherwise, you could try logging a bug to have support for null ids added.

like image 185
James Avatar answered Oct 26 '22 22:10

James