实体“Car”和“Pakete”之间存在多对多关系,我试图通过从两端移除来删除它们之间的链接:
public Pakete removeAllLinksFromPacket(int packetId) {
Pakete p = em.find(Pakete.class, packetId);
if ( null != p ) {
for(Car c : p.getCars() ) {
c.getPakets().remove(p);
// em.merge(c);
}
p.getCars().clear();
// em.merge(p);
// em.flush();
}
return p;
}
当我执行上面的代码时,会在当前会话的持久化上下文中删除链接,但是更改不会同步到db。如果我然后停止并重新启动会话,链接会再次出现:-(。注释掉的em.merge()和em.flush()es只是一次绝望的尝试。
服务器是glassfish 3.1.2
实体看起来如下:
@Table(name="cars")
public class Car implements Serializable {
@EmbeddedId
private CarPK id;
//bi-directional many-to-many association to Pakete
@ManyToMany
@JoinTable(
name="cars_pakete"
, joinColumns={
@JoinColumn(name="uid", referencedColumnName="uid"),
@JoinColumn(name="car_name", referencedColumnName="name"),
}
, inverseJoinColumns={
@JoinColumn(name="paket_id")
}
)
private Set<Pakete> paketes;
public Car() {
}
public CarPK getId() {
return this.id;
}
public void setId(CarPK id) {
this.id = id;
}
// ... other members getter/setter removed
}
和
@Table(name="pakete")
public class Pakete implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
// ... some member variables removed
//bi-directional many-to-many association to Car
@ManyToMany(mappedBy="paketes")
private Set<Car> cars;
public Pakete() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public Set<Car> getCars() {
return this.cars;
}
public void setCars(Set<Car> cars) {
this.cars = cars;
}
// ... some getter/setter removed
}
现有的数据库和我使用eclipse jpa工具生成了上述实体。
我错过了什么。作为一种解决方法,我可以在连接表上执行本机查询。但我并没有放弃希望有人能解释我在这里发生了什么。
提前致谢。
我将代码更改为:
public Pakete removeAllLinksFromPacket(int packetId) {
Pakete p = em.find(Pakete.class, packetId);
if ( null != p ) {
List<Car> lc = new ArrayList<Car>();
lc.addAll(p.getCars());
if ( lc.isEmpty() )
throw new NullPointerException("no links");
for(Car c : lc ) {
if ( !c.getPaketes().contains(p) )
throw new NullPointerException("no packet");
c.getPaketes().remove(p);
if ( !p.getCars().contains(c) )
throw new NullPointerException("no car");
p.getCars().remove(c);
}
} else
throw new NullPointerException("No packet found");
return p;
}
并添加了一些类似断言的异常以确保。它没有提供任何线索。
在一个用例中,函数本身由另一个函数调用,该函数首先删除所有链接,然后添加新链接。它看起来像这样:
@Override
public void mapCarsToPacket(int packetId,
List<String> carNames) {
// 1. remove all existing links
Pakete p = eao.removeAllLinksFromPacket(packetId);
// 2. add the new links
for (String cn : carNames ) {
List<Car> cars = eao.getCarsWithName(cn);
for(Car c : cars ) {
p.getCars().add(c);
c.getPaketes().add(p);
}
}
}
所以这个函数在一个事务中运行,当我执行它时,旧的数据包仍然没有从db 中删除,但插入了新的链接。然后,数据库包含新列表和旧列表。当列表重叠时,例如新列表包含已链接的汽车,由于存在唯一约束违规,我收到了DBException。
但是,如果数据包本身被删除如下:
public void deletePacketAndAllItsLinks(int id) {
Pakete p = removeAllLinksFromPacket(id);
if ( null != p ) {
em.remove(p);
}
}
哦,不知道,连接表中的数据包及其所有链接都被删除了。
...顿抑
暂时:我放弃了!这真的很糟糕,但它确实有效:
public Pakete removeAllLinksFromPacket(int packetId) {
em.flush();
em.clear();
em.createNativeQuery("DELETE FROM cars_pakete WHERE paket_id=?").setParameter(1, packetId).executeUpdate();
Pakete p = em.find(Pakete.class, packetId);
if ( null != p ) {
List<Car> lc = new ArrayList<Car>();
lc.addAll(p.getCars());
for(Car c : lc ) {
c.getPaketes().remove(p);
p.getCars().remove(c);
}
}
return p;
}
我自己保持持久化上下文同步。这肯定不是JPA的精神,我真的很讨厌它。但是,我可以继续我的项目。感谢任何试图提供帮助的人。任何导致JPA符合解决方案的未来消息都值得欢迎。
答案 0 :(得分:0)
确保在活动事务中进行更改,并确保提交事务。还要确保该集合在开始时不是空的。
尝试启用最好的登录,并包含日志。
答案 1 :(得分:0)
我想我有同样的问题。
我有几乎相同的情况,我在多对多关系中有两个连接列,但只有一个由JPA容器设置。另一个填充空值(但仅在删除时 - >>导致数据库中没有删除任何内容,因为在where子句中使用null值的查询与任何行都不匹配)。插入工作正常,没有任何问题......
也许您可以将语句记录到DBMS并确认?