Java 具有空值的JPA复合主键
我在oracle数据库中有一个包含客户数据的表。以下是一个简化的定义:Java 具有空值的JPA复合主键,java,jpa,eclipselink,jpa-2.0,ejb-3.0,Java,Jpa,Eclipselink,Jpa 2.0,Ejb 3.0,我在oracle数据库中有一个包含客户数据的表。以下是一个简化的定义: CUSTOMER (CUSTOMER_ID NUMBER NOT NULL, SOURCE_SYSTEM VARCHAR2(30), FULL_NAME VARCHAR2(360), PHONE_NUMBER VARCHAR2(240) ) 此表的主键是(客户ID,源系统) 该表有许多行,SOURCE\u SYSTEM为空。在数据库级别,没有问
CUSTOMER (CUSTOMER_ID NUMBER NOT NULL,
SOURCE_SYSTEM VARCHAR2(30),
FULL_NAME VARCHAR2(360),
PHONE_NUMBER VARCHAR2(240)
)
此表的主键是(客户ID,源系统)
该表有许多行,SOURCE\u SYSTEM
为空。在数据库级别,没有问题,但是,当我尝试通过JPA实体访问这些行时,它会导致许多问题:
1:使用em.find()
2:如果记录在表中不存在,则使用em.merge()
向上插入源系统为空的行
成功,但在后续更新时失败,因为合并总是导致运行插入
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))")
不幸的是,“主键不能包含null”似乎是最后一句话。我找不到关于这个错误的解决方法的太多信息,这使得看起来似乎没有解决方案
问题:我想知道是否有人有任何基于Java代码的解决方案不涉及对数据库进行更改。我目前的解决方法是使用行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\u 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
...
}
主键不能包含null(在JPA或数据库中)。使用不同的值,如“或” 客户id是否唯一?如果是这样,那么只需从Id中删除sourceSystem
否则,您可以尝试记录错误以添加对空id的支持。为什么要将空id用于客户id?它看起来应该使用排序,如果它不为null,则应该允许source_系统字段为null。您可以尝试按照此处所述指定要使用的验证,但我不确定您所使用的验证为什么不起作用。但是您要映射customer_id字段两次,因此请确保您正确设置了这两个字段,并打开日志记录,查看您的映射或生成的SQL是否存在问题。对空字段的查询通常必须略有不同,这可能不会发生,因为它是pk检查。描述Eclipselink日志记录
CUSTOMER\u ID
将永远不会为空,并在类中标记为nullable=false
,在数据库中标记为NOT null
,尽管它不基于序列。em.find()
的sql很可能是使用SOURCE\u SYSTEM=''
生成的,而不是SOURCE\u SYSTEM为NULL
,这就是记录未正确返回的原因。我已尝试使用EclipseLink特定的@PrimaryKey
注释和validation=IdValidation.NONE
,,但是最终行为与上面显示的@EmbeddedId
注释完全相同。您确实应该实现equals和hashCode以考虑可空字段。。另请参见CUSTOMER\u ID
不是唯一的,我无法对该表进行更改,因为它已被其他应用程序使用。不幸的是,我无法更改表中现有的空值以满足我自己的需要,因为它会影响当前在SOURCE\u SYSTEM
中预期为空的任何其他应用程序。您能否定义一个二级索引,用合适的占位符替换空字符串?