Java 如果主键不为null,Spring data JPA不允许验证实体

Java 如果主键不为null,Spring data JPA不允许验证实体,java,spring,spring-data,spring-data-jpa,Java,Spring,Spring Data,Spring Data Jpa,我有一个订户实体,它使用用户提供的电子邮件地址作为主键,而不是自动生成的值。这意味着当调用JpaRepository的save方法时,主键值是notnull 春季数据JPA第2.2.1节表2.2说明如下: 默认情况下,SpringDataJPA检查给定对象的Id属性 实体如果Id属性为null,则实体将假定为 新的,否则视为不是新的 此行为防止新订户实体被持久化到数据库。告诉您如何自定义该行为 要么让您的实体实现持久化并覆盖isNew,要么提供实体信息的自定义实现告诉您如何自定义该行为 要么让您

我有一个订户实体,它使用用户提供的电子邮件地址作为主键,而不是自动生成的值。这意味着当调用JpaRepository的save方法时,主键值是notnull

春季数据JPA第2.2.1节表2.2说明如下:

默认情况下,SpringDataJPA检查给定对象的Id属性 实体如果Id属性为null,则实体将假定为 新的,否则视为不是新的

此行为防止新订户实体被持久化到数据库。

告诉您如何自定义该行为

要么让您的实体实现
持久化
并覆盖
isNew
,要么提供
实体信息的自定义实现

告诉您如何自定义该行为


要么让您的实体实现
Persistable
并覆盖
isNew
,要么提供
EntityInformation

的自定义实现在决定如何选择实体的主键时,我们有两个选项。 1.使用Spring提供的自动生成密钥 2.使用自定义主键,例如电子邮件地址

自动生成的密钥更易于使用。在持久化实体时,Spring注意到id字段为空,并断定这是一个正在持久化的新实体。一个新的自动生成的值被分配给id字段,实体被持久化。但是,如果要确保不保留具有相同电子邮件地址的两个实体,请记住使用
@Column(unique=“true”)
注释电子邮件字段。由于电子邮件字段上的唯一约束,检测重复项也很容易


但是,有时您不希望使用自动生成的密钥,因为您可能希望使用用户提供的电子邮件地址作为密钥。这种方法没有问题。在实体中用@Id标记电子邮件字段。仅此而已。但是,重复检测是不可能的。如果多次收到创建具有相同电子邮件地址的实体的请求,则每次都会更新相同的实体,即每次都会执行
EntityManager.merge()
。将不会引发约束冲突异常。回想一下,Spring总是检查主键字段是否为空,以决定是创建新实体还是合并到现有实体中。

在决定如何选择实体的主键时,我们有两个选项。 1.使用Spring提供的自动生成密钥 2.使用自定义主键,例如电子邮件地址

自动生成的密钥更易于使用。在持久化实体时,Spring注意到id字段为空,并断定这是一个正在持久化的新实体。一个新的自动生成的值被分配给id字段,实体被持久化。但是,如果要确保不保留具有相同电子邮件地址的两个实体,请记住使用
@Column(unique=“true”)
注释电子邮件字段。由于电子邮件字段上的唯一约束,检测重复项也很容易


但是,有时您不希望使用自动生成的密钥,因为您可能希望使用用户提供的电子邮件地址作为密钥。这种方法没有问题。在实体中用@Id标记电子邮件字段。仅此而已。但是,重复检测是不可能的。如果多次收到创建具有相同电子邮件地址的实体的请求,则每次都会更新相同的实体,即每次都会执行
EntityManager.merge()
。将不会引发约束冲突异常。回想一下,Spring总是检查主键字段是否为空,以决定是创建新实体还是合并到现有实体中。

不应该。当repo看到输入实体中存在ID时,它将在内部调用
EntityManager.merge()
,该函数仍将保存实体。您只需要记住将
repository.save()的返回值作为托管entity@AdrianShum你说得对。现在可以了。但是,不会检测到重复项。如果我尝试保存同一个实体两次,第二次它不会给出一个重复的异常,因为我使用了自动生成的键。而是更新同一个实体,这不是我想要的。它不应该。当repo看到输入实体中存在ID时,它将在内部调用
EntityManager.merge()
,该函数仍将保存实体。您只需要记住将
repository.save()的返回值作为托管entity@AdrianShum你说得对。现在可以了。但是,不会检测到重复项。如果我尝试保存同一个实体两次,第二次它不会给出一个重复的异常,因为我使用了自动生成的键。而是更新了相同的实体,这不是我想要的。我可以调用findByEmail()并检查实体是否存在。但是这需要一个额外的数据库操作,我想避免这个操作。你是说你不知道如何确定你的实体是否是新的,但是希望Spring数据能够直接完成吗?我担心这要求有点过分。在我之前对你的评论之后,我想出了如何使用电子邮件id作为密钥。你可以参考我上面对@AdrianShum的评论。现在的问题是save也会更新实体,而不是给出重复的异常。我知道isNew()方法。我可以调用findByEmail()并检查实体是否存在。但是这需要一个额外的数据库操作,我想避免这个操作。你是说你不知道如何确定你的实体是否是新的,但是希望Spring数据能够直接完成吗?我担心这要求有点过分。在我之前对你的评论之后,我想出了如何使用电子邮件id