Eins-zu-viele-Beziehung: Update entfernt Kinder mit JPA 2.0

Habe ich eine bidirektionale eins-zu-viele-Beziehung.

0 oder 1 client <-> Liste von 0 oder mehr Produkt-Bestellungen.

Beziehung gesetzt werden sollten, oder unset auf beide Entitäten:
Auf der client-Seite, ich möchte, um die Liste der Bestellungen von Produkten, die der client zugewiesen; der client sollte dann set /unset um die Bestellungen automatisch gewählt.
Auf der Produkt-Seite, um, ich möchte den client, zu dem der oder zugewiesen; das Produkt bestellen, sollten dann entfernt werden aus den zuvor assiged client-Liste Hinzugefügt und der neue zugewiesene client-Liste.

Will ich mit reinen JPA 2.0 annotations und ein "merge" - Aufruf der entity-manager (nur mit cascade-Optionen). Ich habe versucht mit dem folgenden code-Stück, aber es funktioniert nicht (ich benutze EclipseLink 2.2.0 als Persistenz-provider)

@Entity
public class Client implements Serializable {
    @OneToMany(mappedBy = "client", cascade= CascadeType.ALL)
    private List<ProductOrder> orders = new ArrayList<>();

    public void setOrders(List<ProductOrder> orders) {
        for (ProductOrder order : this.orders) {
            order.unsetClient();
            //don't use order.setClient(null);
            //(ConcurrentModificationEx on array)
            //TODO doesn't work!
        }
        for (ProductOrder order : orders) {
            order.setClient(this);
        }
        this.orders = orders;
    }

    //other fields /getters /setters
}

@Entity
public class ProductOrder implements Serializable {
    @ManyToOne(cascade= CascadeType.ALL)
    private Client client;

    public void setClient(Client client) {
        //remove from previous client
        if (this.client != null) {
            this.client.getOrders().remove(this);
        }

        this.client = client;

        //add to new client
        if (client != null && !client.getOrders().contains(this)) {
            client.getOrders().add(this);
        }
    }

    public void unsetClient() {
        client = null;
    }

    //other fields /getters /setters
}

Fassade code für die Persistenz-client:

//call setters on entity by JSF frontend...
getEntityManager().merge(client)

Fassade code für die Persistenz Produkt Reihenfolge:

//call setters on entity by JSF frontend...
getEntityManager().merge(productOrder)

Beim ändern der client-Einsatz auf der um Seite, es funktioniert gut: Auf der client-Seite, wird die Bestellung entfernt von der vorherigen client-Liste und wird Hinzugefügt, um die neuen client-Liste (falls zugewiesen).

ABER beim Wechsel auf der client-Seite, kann ich nur hinzufügen, Bestellungen (auf der Bestellseite, Zuordnung zu den neuen client ausgeführt wird), aber es einfach ignoriert, wenn ich Aufträge entfernen aus der Liste des Clients (nach dem speichern und erfrischend, Sie sind immer noch in der Liste auf der client-Seite, und auf der um Seite, Sie sind auch noch zugewiesen, um den vorherigen client.

Nur zur Klarstellung, ich NICHT verwenden möchten, ein "delete-orphan" - option: Beim entfernen eines Auftrags aus der Liste, sollte es nicht aus der Datenbank gelöscht werden, sondern seine Zuordnung client aktualisiert werden soll (also auf null), wie definiert in den Client#setOrders Methode. Wie kann dies werden erreicht?


BEARBEITEN: Dank der Hilfe, die ich hier hatte, war ich in der Lage, dieses problem zu beheben. Siehe meine Lösung unter:

Client ("Ein" /"Eigentum" Seite) speichert die Bestellungen, die geändert wurden, werden in ein temporäres Feld.

@Entity
public class Client implements Serializable, EntityContainer {

    @OneToMany(mappedBy = "client", cascade= CascadeType.ALL)
    private List<ProductOrder> orders = new ArrayList<>();

    @Transient
    private List<ProductOrder> modifiedOrders = new ArrayList<>();

    public void setOrders(List<ProductOrder> orders) {
    if (orders == null) {
        orders = new ArrayList<>();
    }

    modifiedOrders = new ArrayList<>();
    for (ProductOrder order : this.orders) {
        order.unsetClient();
        modifiedOrders.add(order);
        //don't use order.setClient(null);
        //(ConcurrentModificationEx on array)
    }

    for (ProductOrder order : orders) {
        order.setClient(this);
        modifiedOrders.add(order);
    }

    this.orders = orders;
    }

    @Override //defined by my EntityContainer interface
    public List getContainedEntities() {
        return modifiedOrders;
}

Auf dem Fassade, wenn anhaltende, prüft es, ob es irgendwelche Personen, dass muss beibehalten werden, auch. Beachten Sie, dass ich verwendet eine Schnittstelle zu Kapseln diese Logik wie meine Fassade ist tatsächlich generic.

//call setters on entity by JSF frontend...
getEntityManager().merge(entity);

if (entity instanceof EntityContainer) {
    EntityContainer entityContainer = (EntityContainer) entity;
    for (Object childEntity : entityContainer.getContainedEntities()) {
        getEntityManager().merge(childEntity);
    }
}

InformationsquelleAutor SputNick | 2012-05-17

Schreibe einen Kommentar