我有一个存储任务的表,以及一个存储该任务的有序步骤的表。步骤属于任务父级(因此任务与步骤具有一对多关系),并且每个步骤都有一个“序数” - 它是哪个步骤号。我希望序号和父任务 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 来做到这一点?
最佳答案
不确定它是否真的解决了问题,但我认为你应该将集合建模为 map :
@OneToMany
@MapKeyJoinColumn(Name="ordinal")
private Map<Long,Step> steps;
当您在中间的某个位置添加步骤时,您有责任更新整个 map 。
如果您仍然需要步骤中的序数,则必须将其设置为只读:
@Column(nullable = false, name = "ordinal", insertable=false, updateable=false)
private Long ordinal;
关于java - 使用 "pure"Hibernate/JPA 一次更新唯一列中的多个条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44928006/