我有 Person 实体,它与 Location 实体组合
@ManyToOne(fetch = FetchType.EAGER, cascade =
{ CascadeType.PERSIST, CascadeType.MERGE })
@Cascade(
{org.hibernate.annotations.CascadeType.SAVE_UPDATE })
public Location getLocation()
{
return location;
}
位置实体的名称为 Id
@Id
public String getName()
{
return name;
}
当 Person 的位置在 Spring MVC 表单中从 L1 更改为 L2 时,我收到以下异常,其中此 Person 实体是表单的 modelAttribute。
org.springframework.orm.hibernate3.HibernateSystemException:identifier of an instance of com.x.y.z.Location was altered from L2 to L1; nested exception is org.hibernate.HibernateException: identifier of an instance of com.x.y.z.Location was altered from L2 to L1
最佳答案
你很困惑Composition与 Association .
你映射的是一个关联; Hibernate (JPA) 中的组合通过 @Embeddable
/@Embedded
注释进行映射。关联是不同实体之间的关系;它们通常通过实体标识符(数据库中的外键)连接。
在您的特定情况下,Person
实体指向Location
实体,这意味着在数据库PERSONS
表中有一个LOCATION_ID
外键(名称可能不同)到 LOCATIONS
表。您想要做的是更新 Location
端的该键,这是非法的,因为它会切断 Hibernate 的关系(另一端在内部仍然保留以前的键值)。
主键通常应该是代理键并且一开始就不可更新;如果您确实需要“更新”它,则必须取消 Location
与 Person
的关联,更新 Location
并将其分配给 再次 Person
或创建一个全新的 Location
实例并将其分配给您的 Person
。
总而言之,如果您确实尝试对组合关系进行建模,则需要将 @ManyToOne 替换为 @Embedded 并相应地更改表架构。这是一个链接 关于 mapping components 的 Hibernate 注解文档.
此外,在两个单独的注释(JPA 与 Hibernate 扩展)中指定级联类型也不是一件好事。如果您确实需要 Hibernate 扩展(在本例中您不需要),只需使用它并将 JPA 注释中的 cascade
属性留空即可。
关于java - 复合实体的更新失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1341889/