【发布时间】:2022-01-14 07:28:25
【问题描述】:
我正在尝试使用 Hibernate 保存一个复杂实体,其中我们有多个具有复合键的实体。 当我尝试保存时,Hibernate 似乎没有从具有复合键的子实体上的某些列中正确检索值,因此 postgre 返回非空违规错误。
@Entity
@Table(name = "activities", schema = "ptw")
@Data
@TypeDefs({
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class),
@TypeDef(name = "pg-id-uuid", typeClass = PostgresIdUUIDType.class)
})
public class Activity extends AuditAtBy implements Serializable {
@EmbeddedId
private CommonId commonId;
@MapsId("siteId")
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE)
@Type(type = "pg-id-uuid")
@JoinColumn(name="site_id",referencedColumnName = "id", columnDefinition = "uuid", updatable = false)
private Site site;
@ManyToOne()
@JoinColumnsOrFormulas(value = {
@JoinColumnOrFormula(formula = @JoinFormula(value="location_id", referencedColumnName = "id")),
@JoinColumnOrFormula(formula = @JoinFormula(value="site_id", referencedColumnName = "site_id"))})
@Type(type = "pg-id-uuid")
@OnDelete(action = OnDeleteAction.CASCADE)
private Location location;
@ManyToOne
@JoinColumns({
@JoinColumn(name = "job_pack_id", referencedColumnName = "id", columnDefinition = "uuid", insertable = false, updatable = false),
@JoinColumn( name = "site_id", referencedColumnName="site_id", columnDefinition = "uuid", insertable = false, updatable = false)
})
@Type(type = "pg-id-uuid")
@OnDelete(action = OnDeleteAction.CASCADE)
private JobPack jobPack;
@Column(name = "permit_number", nullable = false, length = 10)
private String permitNumber;
@Column(name = "order_number", nullable = false)
private short orderNumber;
@Column(name = "location_name", length = 200)
private String locationName;
**@ManyToOne
@JoinColumns({
@JoinColumn(name = "state_id", referencedColumnName="id", columnDefinition = "uuid", insertable = false, updatable = false),
@JoinColumn(name = "site_id", referencedColumnName="site_id", columnDefinition = "uuid", insertable = false, updatable = false)
})
@Type(type = "pg-id-uuid")
private ActivityState state;**
@ManyToOne
@JoinColumns({
@JoinColumn(name = "activity_type_id", referencedColumnName="id", columnDefinition = "uuid", insertable = false, updatable = false),
@JoinColumn(name = "site_id", referencedColumnName="site_id", columnDefinition = "uuid", insertable = false, updatable = false)
})
@Type(type = "pg-id-uuid")
@OnDelete(action = OnDeleteAction.CASCADE)
private ActivityType activityType;
public UUID getId(){
return this.getCommonId().getId();
}
public void setId(UUID id){
if (this.getCommonId() == null) {
this.setCommonId(new CommonId());
}
this.getCommonId().setId(id);
}
public void setSite(Site site){
this.site = site;
if (this.getCommonId() == null) {
this.setCommonId(new CommonId());
}
this.getCommonId().setSiteId(site.getId());
}
}
在使用映射器从 DTO 转换为实体时,会覆盖 setId/getId/setSite 以更新实体
ActivityState如下:
@Entity
@Table(name = "activity_states", schema = "ptw")
@Data
@TypeDefs({
@TypeDef(name = "pg-id-uuid", typeClass = PostgresIdUUIDType.class)
})
public class ActivityState extends AuditAtBy implements Serializable {
@EmbeddedId
private CommonId commonId;
@MapsId("siteId")
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE)
private Site site;
@Column(nullable = false, length = 50)
private String name;
@Column(name = "icon_id", nullable = false)
private short iconId;
@Column(name = "is_initial", nullable = false)
private boolean isInitial;
@Column(name = "order_number", nullable = false)
private short orderNumber;
public UUID getId(){
return this.getCommonId().getId();
}
public void setId(UUID id){
if (this.getCommonId() == null) {
this.setCommonId(new CommonId());
}
this.getCommonId().setId(id);
}
public void setSite(Site site){
this.site = site;
if (this.getCommonId() == null) {
this.setCommonId(new CommonId());
}
this.getCommonId().setSiteId(site.getId());
}
}
当我尝试保存异常时:
Caused by: org.postgresql.util.PSQLException: ERROR: null value in column "state_id" violates not-null constraint
Detail: Failing row contains (c821ff72-de93-4c03-abf5-e18347c29955, null, 0, 5081790f-19ed-44e0-be17-94f94aed878b, null, null, test, test, null, 1, 1, f, N/A, 1, null, null, null, null, null, null, null, null, null, null, null, f, {"title": "test", "DateTable": {"timeTo": "", "timeFrom": "", "v..., 2021-12-09 13:46:02.829157+01, 2021-12-09 13:46:02.829157+01, 7b0702c7-9f11-4a92-bfdf-7f98eb8ac94d, 7b0702c7-9f11-4a92-bfdf-7f98eb8ac94d, null, null, f).
尽管我尝试了多种更改映射和关系的方法,但我不知道如何解决。 我知道复合键不是最好的方法,但我们有一个多租户系统,其中保持数据隔离的最佳方法就是这个。
【问题讨论】:
-
您对
insertable = false, updatable = false有什么期望?您已强制 HBN 不在 DB 中填充 state_id 的值,而 HBD 没有这样做。 -
没有它,我无法映射实体。当我尝试删除该值时,我设置了这个:实体映射中的重复列:com.basf.swift.ptw.model.entity.Activity 列:site_id(应该用 insert="false" update="false" 映射)因为我需要将多个实体映射到同一列 site_id。
-
已修复:stackoverflow.com/questions/4231452/… 使用 @JoinColumnsOrFormulas 允许我们删除 insertable= false 并使其正常工作。
-
为什么不将那个 state_id 连接列标记为 insertable=true?您可以将其他 site_id 连接列保留为 insertable/updatable=false 以避免它被更改并影响实体的身份。
-
其实你做不到。启动应用程序时 HIbernate 将失败,JoinColumns 注释中的所有列都需要具有相同的标志,因此两者或它们都可插入或不可插入。为了避免这个问题,我们发现这种方法是可行的。 @JoinColumnsOrFormulas(value = { @JoinColumnOrFormula(column = @JoinColumn(name="state_id", referencedColumnName = "id")), @JoinColumnOrFormula(formula = @JoinFormula(value="site_id", referencedColumnName = "site_id")) } )
标签: java spring hibernate jpa spring-data-jpa