从多对多删除不与db同步

时间:2012-08-27 10:13:49

标签: java-ee jpa glassfish many-to-many

实体“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符合解决方案的未来消息都值得欢迎。

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

我想我有同样的问题。

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

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