我有一个存储任务的表,以及一个存储该任务的有序步骤的表。步骤属于任务父级(因此任务与步骤具有一对多的关系),并且每个步骤都有一个“序数” - 它是步骤编号。我希望序数和父任务ID是一个组合的唯一约束,因此例如单个任务不能用两个不同的步骤设置为“步骤1”,但不同的任务可以各自拥有自己的“步骤” 1" 。
我希望能够同时更新属于任务的每个步骤的序数,这样我就不会违反唯一约束。因此,如果我有“步骤1”,“步骤2”和“步骤3”,我可以在“步骤2”中插入新步骤并将现有步骤转移到“步骤3”和“步骤4”。我知道某些数据库允许你延迟检查约束,直到提交事务为止,但我非常希望能避免任何需要某种数据库类型的东西,并完全在JPA / Hibernate中完成。
以下是我的实体的简化版本:
任务:
@Table
@Entity
public class Task {
@Version
private Long version;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Step> steps;
}
步骤:
@Entity
@Table(
uniqueConstraints = {
@UniqueConstraint(
name = "UX_Step_Parent_Ordinal",
columnNames = {"parent_id", "ordinal"})
}
)
public class Step {
@Version
private Long version;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false, name = "ordinal")
private Long ordinal;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "parent_id")
private Task parent;
}
到目前为止,我提出的唯一方法是首先在最后插入新步骤,然后动态生成如下所示的HQL查询,该查询一次更新特定任务中的每一步案例:
UPDATE Step s
SET s.ordinal = CASE
WHEN (s.id = 55) THEN 1
WHEN (s.id = 58) THEN 2
WHEN (s.id = 47) THEN 3
WHEN (s.id = 33) THEN 4
... etc
ELSE 0 END
WHERE s.parent.id = 5
但是我很确定这需要引擎在每次发生时重新处理查询,因此无法利用查询缓存或其他加速等功能。还有其他方法可以使用Hibernate / JPA吗?
答案 0 :(得分:1)
不确定它是否真的能解决问题,但我认为你应该将这个集合建模为地图:
@OneToMany
@MapKeyJoinColumn(Name="ordinal")
private Map<Long,Step> steps;
当您在其间的某处添加Step时,您有责任更新整个地图。
如果您仍然需要步骤中的序数,那么您必须将其设为readOnly:
@Column(nullable = false, name = "ordinal", insertable=false, updateable=false)
private Long ordinal;