JPA 和 Hibernate 的组合键
Composite Key with JPA and Hibernate
在此代码中,我尝试使用该模型生成复合键 class,但是当我执行 post 方法时抛出异常。
我正在使用 postgres 作为数据库。然后我需要休眠自动生成“RA”和 Idprojeto。
模型 ID class
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@AllArgsConstructor
@NoArgsConstructor
class ProjetoId implements Serializable{
Long idProjeto;
Long ra;
}
模型实体
@Entity
@Data
@IdClass(ProjetoId.class)
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Table(name = "projeto", schema = "public")
public class Projeto {
@EqualsAndHashCode.Include
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_projeto")
private Long idProjeto;
@Valid
@ConvertGroup(from = Default.class, to = ValidationGroups.ClienteId.class)
@NotNull
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "id_cliente")
private Cliente cliente;
@Valid
@NotNull
@ElementCollection
private List<ProdutoToProjeto> produtos = new ArrayList<>();
@EqualsAndHashCode.Include
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ra")
private Long ra;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@Enumerated(EnumType.STRING)
@Column(name = "situacao")
private StatusProjeto situacao;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@Column(name = "data_criacao")
private LocalDate dataRegistro;
public void finalizar() {
if(naoPodeSerFinalizado()) {
throw new ProjetoException("Projeto não pode ser finalizado");
}
setSituacao(StatusProjeto.APROVADO);
}
public void cancelar() {
if(naoPodeSerFinalizado()) {
throw new ProjetoException("Projeto não pode ser cancelado");
}
setSituacao(StatusProjeto.RECUSADO);
}
public boolean podeSerFinalizado() {
return StatusProjeto.PEDENTE.equals(getSituacao());
}
public boolean naoPodeSerFinalizado() {
return !podeSerFinalizado();
}
}
错误
java.lang.IllegalArgumentException: Can not set java.lang.Long field com.ciasense.apiciasense.model.ProjetoId.ra to org.hibernate.id.IdentifierGeneratorHelper
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167) ~[na:na]
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171) ~[na:na]
at java.base/jdk.internal.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81) ~[na:na]
at java.base/java.lang.reflect.Field.set(Field.java:778) ~[na:na]
如果您使用 DB SEQUENCE 作为自动生成类型,那么组合键才可以工作。否则,您必须编写自定义键生成器并在插入之前为复合键的两个字段分配值。
@EqualsAndHashCode.Include
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "id_projeto")
private Long idProjeto;
@EqualsAndHashCode.Include
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "ra")
private Long ra;
如果我明白了,你想做一个关键合成?
如果是,您有两件事要做:
1- 像您一样用 @IdClass 注释您的 class 并将 @Id 放在您想要的属性上 link 使用您的键和 Equals 和 HashCode 方法(您的 IDE 生成它很容易)。 (这件事已经为你做好了)
2- 在您的存储库中,您必须像普通密钥一样定义您的密钥
示例:(似乎没有完成,它是扩展class中的“ProjetoId”)
@Repository
public interface ProjetoRepository extends JpaRepository<Projeto, ProjetoId> {
List<Projeto> findByDataRegistro(Date date);
}
你也可以去看baeldung,比我解释的更详细
在此代码中,我尝试使用该模型生成复合键 class,但是当我执行 post 方法时抛出异常。
我正在使用 postgres 作为数据库。然后我需要休眠自动生成“RA”和 Idprojeto。
模型 ID class
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@AllArgsConstructor
@NoArgsConstructor
class ProjetoId implements Serializable{
Long idProjeto;
Long ra;
}
模型实体
@Entity
@Data
@IdClass(ProjetoId.class)
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Table(name = "projeto", schema = "public")
public class Projeto {
@EqualsAndHashCode.Include
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_projeto")
private Long idProjeto;
@Valid
@ConvertGroup(from = Default.class, to = ValidationGroups.ClienteId.class)
@NotNull
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "id_cliente")
private Cliente cliente;
@Valid
@NotNull
@ElementCollection
private List<ProdutoToProjeto> produtos = new ArrayList<>();
@EqualsAndHashCode.Include
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ra")
private Long ra;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@Enumerated(EnumType.STRING)
@Column(name = "situacao")
private StatusProjeto situacao;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@Column(name = "data_criacao")
private LocalDate dataRegistro;
public void finalizar() {
if(naoPodeSerFinalizado()) {
throw new ProjetoException("Projeto não pode ser finalizado");
}
setSituacao(StatusProjeto.APROVADO);
}
public void cancelar() {
if(naoPodeSerFinalizado()) {
throw new ProjetoException("Projeto não pode ser cancelado");
}
setSituacao(StatusProjeto.RECUSADO);
}
public boolean podeSerFinalizado() {
return StatusProjeto.PEDENTE.equals(getSituacao());
}
public boolean naoPodeSerFinalizado() {
return !podeSerFinalizado();
}
}
错误
java.lang.IllegalArgumentException: Can not set java.lang.Long field com.ciasense.apiciasense.model.ProjetoId.ra to org.hibernate.id.IdentifierGeneratorHelper
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167) ~[na:na]
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171) ~[na:na]
at java.base/jdk.internal.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81) ~[na:na]
at java.base/java.lang.reflect.Field.set(Field.java:778) ~[na:na]
如果您使用 DB SEQUENCE 作为自动生成类型,那么组合键才可以工作。否则,您必须编写自定义键生成器并在插入之前为复合键的两个字段分配值。
@EqualsAndHashCode.Include
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "id_projeto")
private Long idProjeto;
@EqualsAndHashCode.Include
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "ra")
private Long ra;
如果我明白了,你想做一个关键合成? 如果是,您有两件事要做:
1- 像您一样用 @IdClass 注释您的 class 并将 @Id 放在您想要的属性上 link 使用您的键和 Equals 和 HashCode 方法(您的 IDE 生成它很容易)。 (这件事已经为你做好了)
2- 在您的存储库中,您必须像普通密钥一样定义您的密钥 示例:(似乎没有完成,它是扩展class中的“ProjetoId”)
@Repository
public interface ProjetoRepository extends JpaRepository<Projeto, ProjetoId> {
List<Projeto> findByDataRegistro(Date date);
}
你也可以去看baeldung,比我解释的更详细