我有以下映射:
参数:
public class Parameter extends Model {
@Id
public long id;
@OneToMany(cascade = CascadeType.ALL)
@OrderBy("parameter DESC")
public List<Attribute> attributes = new ArrayList<Attribute>();
}
属性:
public class Attribute extends Model {
@Id
public long id;
@ManyToOne(cascade = CascadeType.ALL)
@JsonIgnore
public Parameter parameter;
}
我在控制器中有一个delete()方法:
public Result deleteAttribute(attributeId) {
Attribute a = Attribute.find.byId(attributeId);
if (a == null) {
return notFound();
}
a.delete();
return ok();
}
调用此方法时,一切正常,属性记录将被删除。但是,属于同一参数的所有其他记录也将被删除。
我的映射有什么问题?不应该cascade = CascadeType.ALL
意味着删除拥有Parameter
会删除属性吗?
答案 0 :(得分:1)
使用CascadeType.ALL
或CascadeType.REMOVE
时,这是预期的行为。如 JPA 2.0规范(JSR-317)中所述,章节 3.2.3删除:
如果
X
是托管实体,则删除操作会使其成为托管实体 除去。删除操作级联到X
引用的实体, 如果从X
到这些其他实体的关系用注释cascade=REMOVE
或cascade=ALL
注释元素值。
在您的情况下,X
由a
表示,因此EntityManager.remove
操作会导致a
与引用的参数实例一起删除。此外,如果删除了任何引用的参数实例,则级联操作会隐式删除其列表中的相应属性。
旁注:双向关系中缺少mappedBy
并未指定所有者(包含FK的关系的拥有方)并导致包含两个外键的其他连接表被视为JPA陷阱
我建议稍微修改一下这种关系,例如:
// Parameter
@OneToMany(mappedBy = "parameter", cascade = ALL) // the non-owning
@OrderBy("parameter DESC")
public List<Attribute> attributes = new ArrayList<Attribute>();
// Attribute
@ManyToOne(cascade = { DETACH, MERGE, PERSIST, REFRESH }) // the owning
@JsonIgnore
public Parameter parameter;
这样只会删除a
及其引用的参数实例。