2

我在实体“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 符合解决方案的建议。

4

2 回答 2

0

我想我有同样的问题。

我有几乎相同的情况,我在多对多关系中有两个连接列,但只有一个是由 JPA 容器设置的。另一个填充了空值(但仅当删除 -> 导致数据库上没有任何内容被删除时,因为 where 子句中具有空值的查询不匹配任何行)。插入工作正常,没有任何问题...

也许您可以将语句记录到您的 DBMS 并确认?

于 2013-04-20T08:01:39.297 回答
0

确保在活动事务中进行更改,并提交事务。还要确保集合开始时不是空的。

尝试启用最好的登录,并包含日志。

于 2012-08-27T14:41:58.137 回答