我在实体“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;
}
当我执行上面的代码时,链接会在当前会话的持久性上下文中被删除,但是更改不会同步到数据库。如果我然后停止并重新启动会话,链接会再次出现:-(。注释掉的 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);
}
}
}
所以这个函数在一个事务中运行,当我执行它时,旧的数据包仍然没有从数据库中删除,但是新的链接被插入了。然后数据库包含新的和旧的列表。当列表重叠时,例如新列表包含已经链接的汽车,由于违反唯一约束,我得到一个 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 符合解决方案的建议。