如何在 JPA 中删除具有外部主键的对象?
How can I remove an object with a foreign primary key in JPA?
我总是被告知,在双向关系的情况下,您可以按如下方式删除您的实体:
- 关系破裂
- 更新所有者实体
- 删除实体
但现在我的主键是关系的一部分,所以这不再可能了。
有人知道在这种情况下如何删除具有主外键的实体吗?
我尝试将 "mappedby" 属性 设置为 null 而不仅仅是调用 manager.remove(...),但总有另一个实体管理器仍然有一个已删除实体的托管实例,因此出现以下错误:
During synchronization a new object was found through a relationship
that was not marked cascade PERSIST
下面我放了我正在使用的 classes 的代码。
这里的classOrderBill
有指向OrderWeek
的主外键。这个主键也是一个组合键,遗憾的是代码的可读性有点差,但它不应该对我遇到的问题有任何影响。
public class OrderBill{
@EmbeddedId
private OrderWeekPK orderWeekPK;
@OneToOne
@JoinColumns(value = {
@JoinColumn(name="weekNr", referencedColumnName = "weekNr"),
@JoinColumn(name="yearNr", referencedColumnName = "yearNr")})
@MapsId
private OrderWeek orderWeek;
}
public class OrderWeek{
@OneToOne(mappedBy="orderWeek")
private OrderBill orderBill;
@EmbeddedId
private OrderWeekPK orderWeekPK;
}
@Embeddable
public class OrderWeekPK implements Serializable{
@Column(name="yearNr")
private int yearNr;
@Column(name="weekNr")
private int weekNr;
}
是否有我缺少的策略?
更新:现在我可以通过切换拥有方和被拥有方来规避这个问题(将mappedby转移到OrderBill
class)。现在我可以在不触及外主键的情况下打破关系。
这个 "solution" 仍然不理想:OrderWeek
现在有一个冗余列(例如 weekNr2 和 yearNr2)与主键相同(或应该)
也许这可以帮助遇到相同问题的人,直到找到实际的解决方案。
您可以通过在 orderWeek 属性 上使用 @Id 并在实体上指定 @IdClass(OrderWeekPK.class) 来取消 @MapsId 并将其嵌入到 OrderBill 中 - 这可能适用于您的映射,但不是您在 post 中提到的错误的来源。
问题是您有两个具有双向关系的实体。如果您更改关系(例如将其取消),则需要将此更改合并到上下文中。因此,要删除 OrderBill 实例,您必须对该实例调用 em.remove 并清空 OrderWeek 引用,然后在 OrderWeek 上调用 merge。这需要在同一个事务中完成,虽然对 OrderWeek 的 orderBill 引用的更改是数据库中的空操作,但它将保持缓存不同步并防止 OrderBill 被复活(或您看到的异常)
另一种方法是将孤立删除标记添加到 OrderWeek 的 orderBill 属性,这会导致 JPA 在您取消此引用时自动调用 em.remove。
我总是被告知,在双向关系的情况下,您可以按如下方式删除您的实体:
- 关系破裂
- 更新所有者实体
- 删除实体
但现在我的主键是关系的一部分,所以这不再可能了。
有人知道在这种情况下如何删除具有主外键的实体吗?
我尝试将 "mappedby" 属性 设置为 null 而不仅仅是调用 manager.remove(...),但总有另一个实体管理器仍然有一个已删除实体的托管实例,因此出现以下错误:
During synchronization a new object was found through a relationship
that was not marked cascade PERSIST
下面我放了我正在使用的 classes 的代码。
这里的classOrderBill
有指向OrderWeek
的主外键。这个主键也是一个组合键,遗憾的是代码的可读性有点差,但它不应该对我遇到的问题有任何影响。
public class OrderBill{
@EmbeddedId
private OrderWeekPK orderWeekPK;
@OneToOne
@JoinColumns(value = {
@JoinColumn(name="weekNr", referencedColumnName = "weekNr"),
@JoinColumn(name="yearNr", referencedColumnName = "yearNr")})
@MapsId
private OrderWeek orderWeek;
}
public class OrderWeek{
@OneToOne(mappedBy="orderWeek")
private OrderBill orderBill;
@EmbeddedId
private OrderWeekPK orderWeekPK;
}
@Embeddable
public class OrderWeekPK implements Serializable{
@Column(name="yearNr")
private int yearNr;
@Column(name="weekNr")
private int weekNr;
}
是否有我缺少的策略?
更新:现在我可以通过切换拥有方和被拥有方来规避这个问题(将mappedby转移到OrderBill
class)。现在我可以在不触及外主键的情况下打破关系。
这个 "solution" 仍然不理想:OrderWeek
现在有一个冗余列(例如 weekNr2 和 yearNr2)与主键相同(或应该)
也许这可以帮助遇到相同问题的人,直到找到实际的解决方案。
您可以通过在 orderWeek 属性 上使用 @Id 并在实体上指定 @IdClass(OrderWeekPK.class) 来取消 @MapsId 并将其嵌入到 OrderBill 中 - 这可能适用于您的映射,但不是您在 post 中提到的错误的来源。
问题是您有两个具有双向关系的实体。如果您更改关系(例如将其取消),则需要将此更改合并到上下文中。因此,要删除 OrderBill 实例,您必须对该实例调用 em.remove 并清空 OrderWeek 引用,然后在 OrderWeek 上调用 merge。这需要在同一个事务中完成,虽然对 OrderWeek 的 orderBill 引用的更改是数据库中的空操作,但它将保持缓存不同步并防止 OrderBill 被复活(或您看到的异常)
另一种方法是将孤立删除标记添加到 OrderWeek 的 orderBill 属性,这会导致 JPA 在您取消此引用时自动调用 em.remove。